package main import ( "database/sql" "encoding/json" "flag" "fmt" "io/ioutil" "log" "os" "os/exec" "path/filepath" "regexp" "sort" "strings" "time" "github.com/gingfrederik/docx" _ "github.com/lib/pq" ) type Config struct { DBHost string `json:"db_host"` DBPort int `json:"db_port"` DBUser string `json:"db_user"` DBPassword string `json:"db_password"` DBName string `json:"db_name"` } type MetricRecord struct { Hostname string Timestamp time.Time TotalCpu float64 TotalMem float64 DpcInterrupt float64 TopCpuProcesses string TopIoProcesses string NetworkConnections string HungProcesses string } type ProcessCPU struct { ProcessName string `json:"ProcessName"` PID int `json:"PID"` CPUPercent float64 `json:"CPU_Percent"` KernelCPUPercent float64 `json:"Kernel_CPU_Percent"` } type ProcessIO struct { ProcessName string `json:"ProcessName"` PID int `json:"PID"` IODataBytesPersec float64 `json:"IODataBytesPersec"` } type NetConn struct { ProcessName string `json:"ProcessName"` PID int `json:"PID"` RemoteAddress string `json:"RemoteAddress"` RemotePort int `json:"RemotePort"` IOBytesPerSec float64 `json:"IO_BytesPerSec"` } type ProcessHung struct { ProcessName string `json:"ProcessName"` 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 } func sortMap(m map[string]int) []kv { var ss []kv for k, v := range m { ss = append(ss, kv{k, v}) } sort.Slice(ss, func(i, j int) bool { return ss[i].Value > ss[j].Value }) return ss } func isIgnoredProcess(name string) bool { name = strings.ToLower(name) if idx := strings.Index(name, "#"); idx != -1 { name = name[:idx] } ignoreList := map[string]bool{ "idle": true, "_total": true, "taskmgr": true, "wmiprvse": true, "powershell": true, "pwsh": true, "dwm": true, } return ignoreList[name] } func isDevTool(name string) bool { name = strings.ToLower(name) if idx := strings.Index(name, "#"); idx != -1 { name = name[:idx] } devTools := map[string]bool{ "code": true, "eclipse": true, "idea64": true, "java": true, "node": true, "msbuild": true, "docker": true, "git": true, "devenv": true, "python": true, "python3": true, "goland": true, } return devTools[name] } func isSecProc(name string) bool { name = strings.ToLower(name) if idx := strings.Index(name, "#"); idx != -1 { name = name[:idx] } secTools := map[string]bool{ "v3svc": true, "asdsvc": true, "v3main": true, "v3lite": true, "privacyi": true, "piagent": true, "ngm": true, "corebguard": true, "gncsensor": true, "gsagent": true, "gsprotect": true, "gsview": true, "gsflow": true, } return secTools[name] } func isSecDriver(name string) bool { name = strings.ToLower(name) return strings.HasPrefix(name, "v3") || strings.Contains(name, "ahnlab") || strings.Contains(name, "asd") || strings.Contains(name, "privacy") || strings.Contains(name, "piagent") || strings.Contains(name, "somansa") || strings.Contains(name, "ngm") || strings.Contains(name, "gnc") || strings.Contains(name, "gsagent") || strings.Contains(name, "gsprotect") || strings.Contains(name, "gsflow") || strings.Contains(name, "genian") } func getProcessTag(name string) string { if isDevTool(name) { return " πŸ’»[개발/λΉŒλ“œ 도ꡬ]" } if isSecProc(name) { return " πŸ›‘οΈ[λ³΄μ•ˆ ν”„λ‘œκ·Έλž¨]" } return "" } type DetailRecord struct { Category string Content []string } func main() { etlPath := flag.String("etl", "", "뢄석할 .etl 파일 경둜") flag.Parse() configFile, err := ioutil.ReadFile("config.json") if err != nil { log.Fatalf("config.json 읽기 μ‹€νŒ¨: %v", err) } var config Config json.Unmarshal(configFile, &config) dbUrl := fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=disable", config.DBUser, config.DBPassword, config.DBHost, config.DBPort, config.DBName) db, err := sql.Open("postgres", dbUrl) if err != nil { log.Fatalf("DB μ—°κ²° μ‹€νŒ¨: %v", err) } defer db.Close() timestampStr := time.Now().Format("20060102_150405") reportDocx := fmt.Sprintf("Report_%s.docx", timestampStr) reportMd := fmt.Sprintf("Report_%s.md", timestampStr) f := docx.NewFile() var md strings.Builder addH1 := func(text string) { p := f.AddParagraph(); p.AddText(text).Size(20) md.WriteString("# " + text + "\n\n") } addH2 := func(text string) { p := f.AddParagraph(); p.AddText(text).Size(14) md.WriteString("## " + text + "\n\n") } addText := func(text string) { if text != "" { f.AddParagraph().AddText(text).Size(11) } else { f.AddParagraph() } if text != "" { md.WriteString(text + "\n\n") } else { md.WriteString("\n") } } addBoldText := func(text string) { p := f.AddParagraph(); p.AddText("β–Ά " + text).Size(11) md.WriteString("**β–Ά " + text + "**\n\n") } addBullet := func(text string) { f.AddParagraph().AddText(" β€’ " + text).Size(11) md.WriteString("- " + text + "\n") } addRedBullet := func(text string) { p := f.AddParagraph(); p.AddText(" β€’ " + text).Size(11).Color("FF0000") md.WriteString("- πŸ”΄ **" + text + "**\n") } addH1("μ‹œμŠ€ν…œ μ„±λŠ₯ 및 μž₯μ•  원인 뢄석 리포트") addText(fmt.Sprintf("μž‘μ„± μΌμ‹œ: %s", time.Now().Format("2006-01-02 15:04:05"))) addText("") devBuildCount := 0 secInterferenceCount := 0 memSwapCount := 0 var sumDpcInterfered float64 sysKernelHogs := make(map[string]int) sysNetworkHogs := make(map[string]int) sysNetworkHogsMaxIO := make(map[string]float64) 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(` SELECT hostname, timestamp, total_cpu_percent, total_mem_percent, dpc_interrupt_percent, COALESCE(top_cpu_processes::text, '[]'), COALESCE(top_io_processes::text, '[]'), COALESCE(network_connections::text, '[]'), COALESCE(hung_processes::text, '[]') FROM client_metrics ORDER BY timestamp DESC LIMIT 10000 `) if err == nil { defer rows.Close() for rows.Next() { var r MetricRecord err := rows.Scan(&r.Hostname, &r.Timestamp, &r.TotalCpu, &r.TotalMem, &r.DpcInterrupt, &r.TopCpuProcesses, &r.TopIoProcesses, &r.NetworkConnections, &r.HungProcesses) if err != nil { continue } localTimeStr := r.Timestamp.Local().Format("2006-01-02 15:04:05") var cpuProcs []ProcessCPU json.Unmarshal([]byte(r.TopCpuProcesses), &cpuProcs) var ioProcs []ProcessIO json.Unmarshal([]byte(r.TopIoProcesses), &ioProcs) // 🚨 [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 } } 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 secCulprits = append(secCulprits, fmt.Sprintf("%s (Kernel CPU: %.1f%%)", cp.ProcessName, cp.KernelCPUPercent)) } } 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) { sysKernelHogs[cp.ProcessName]++ rec.Content = append(rec.Content, fmt.Sprintf("μ£Όλ²”: %s%s (PID: %d) / 컀널 점유 %.1f%%", cp.ProcessName, getProcessTag(cp.ProcessName), cp.PID, cp.KernelCPUPercent)) } } if len(rec.Content) > 0 { details = append(details, rec) } } // 2. λŒ€μ—­ν­ 포화 isNetworkChoke := false var netRec DetailRecord for _, p := range ioProcs { if p.IODataBytesPersec > 5242880 && !isIgnoredProcess(p.ProcessName) { sysNetworkHogs[p.ProcessName]++ mbps := p.IODataBytesPersec / 1048576.0 if mbps > sysNetworkHogsMaxIO[p.ProcessName] { sysNetworkHogsMaxIO[p.ProcessName] = mbps } if !isNetworkChoke { isNetworkChoke = true isEventOccurred = true netRec = DetailRecord{Category: fmt.Sprintf("[λŒ€μ—­ν­ 포화 감지] λ„€νŠΈμ›Œν¬/λ””μŠ€ν¬ μ§€μ—° - μ‹œκ°„: %s | PC: %s", localTimeStr, r.Hostname)} } var conns []NetConn json.Unmarshal([]byte(r.NetworkConnections), &conns) connStr := "λͺ©μ μ§€ μ—°κ²° μ—†μŒ (λ‚΄λΆ€ λŒ€μš©λŸ‰ 파일 I/O)" for _, c := range conns { if c.ProcessName == p.ProcessName { ipStr := fmt.Sprintf("%s:%d", c.RemoteAddress, c.RemotePort) sysTargetIps[ipStr]++ connMbps := c.IOBytesPerSec / 1048576.0 if connMbps > sysTargetIpsMaxIO[ipStr] { sysTargetIpsMaxIO[ipStr] = connMbps } connStr = fmt.Sprintf("λͺ©μ μ§€ IP: %s (속도: %.1f MB/s)", ipStr, connMbps) break } } netRec.Content = append(netRec.Content, fmt.Sprintf("νŠΈλž˜ν”½ 점유: %s%s (PID: %d) / 총 %.1f MB/s -> %s", p.ProcessName, getProcessTag(p.ProcessName), p.PID, mbps, connStr)) } } if isNetworkChoke { details = append(details, netRec) } // 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)} for _, h := range hung { if !isIgnoredProcess(h.ProcessName) { hungCounts[h.ProcessName]++ hasValidHang = true hangRec.Content = append(hangRec.Content, fmt.Sprintf("멈좀: %s%s (PID: %d)", h.ProcessName, getProcessTag(h.ProcessName), h.PID)) } } if hasValidHang { details = append(details, hangRec) isEventOccurred = true } } // 심화 뢄석: 상관관계 및 μ‹œκ°„λŒ€λ³„ 슀트레슀 좔적 if isNetworkChoke && hasValidHang { networkHangCorrels++ // λŒ€μ—­ν­ 포화가 μ•± μ‘λ‹΅μ—†μŒμ„ μœ λ°œν•œ μ—°κ΄€μ„± μ˜μ‹¬ 사둀 } if isEventOccurred { hourlyStress[r.Timestamp.Hour()]++ } totalEventsParsed++ } } // --- Smoking Gun Report Section --- addH2("🚨 λ³΄μ•ˆ μ†”λ£¨μ…˜ 개발 ν™˜κ²½ 좩돌 μ •λ°€ 뢄석") addText("λ³Έ μ„Ήμ…˜μ€ λ³΄μ•ˆ ν”„λ‘œκ·Έλž¨(λ°±μ‹ /EDR/DLP)이 개발자의 λΉŒλ“œ/컴파일 μž‘μ—…μ— λ―ΈμΉ˜λŠ” μ‹€μ§ˆμ μΈ μ„±λŠ₯ μ €ν•˜ 연관성을 ꡐ차 κ²€μ¦ν•œ κ²°κ³Όμž…λ‹ˆλ‹€.") addText(fmt.Sprintf("뢄석 데이터 λ‚΄ 개발 도ꡬ(IDE, 컴파일러 λ“±) ν™œμ„±ν™” 감지: 총 %d 회", devBuildCount)) addBoldText(fmt.Sprintf("πŸ‘‰ μœ„ λΉŒλ“œ μž‘μ—… 쀑, λ³΄μ•ˆ ν”„λ‘œκ·Έλž¨μ΄ κ°œμž…ν•˜μ—¬ 컀널 프리징/μ‹œμŠ€ν…œ 렉을 μœ λ°œν•œ 횟수: %d 회", secInterferenceCount)) if devBuildCount > 0 { rate := (float64(secInterferenceCount) / float64(devBuildCount)) * 100 addBoldText(fmt.Sprintf("πŸ”₯ λ³΄μ•ˆ μ†”λ£¨μ…˜μœΌλ‘œ μΈν•œ 개발 업무 λ°©ν•΄(병λͺ©) ν™•λ₯ : %.1f%%", rate)) } addText("") // --- General Report --- addH2("1. μ‹œμŠ€ν…œ 체감 λ ‰(Lag) 유발 핡심 μ£Όλ²” μš”μ•½") addBoldText("[프리징 원인] μž₯μ•  μ‹œμ  컀널(EDR/λ°±μ‹ ) 병λͺ© ν”„λ‘œμ„ΈμŠ€") for i, kv := range sortMap(sysKernelHogs) { if i >= 5 { break } addBullet(fmt.Sprintf("%s%s (멈좀 유발 횟수: %d회)", kv.Key, getProcessTag(kv.Key), kv.Value)) } if len(sysKernelHogs) == 0 { addBullet("ν•΄λ‹Ή 원인 μ—†μŒ") } addText("") addBoldText("[μ§€μ—° 원인] μž₯μ•  μ‹œμ  νŠΈλž˜ν”½ 폭주 유발 ν”„λ‘œμ„ΈμŠ€") for i, kv := range sortMap(sysNetworkHogs) { if i >= 5 { break } maxIo := sysNetworkHogsMaxIO[kv.Key] addBullet(fmt.Sprintf("%s%s (포화 유발: %d회 | 졜고 I/O 속도: %.1f MB/s)", kv.Key, getProcessTag(kv.Key), kv.Value, maxIo)) } if len(sysNetworkHogs) == 0 { addBullet("ν•΄λ‹Ή 원인 μ—†μŒ") } addText("") addBoldText("[λŒ€μ—­ν­ 도둑] λ ‰ 유발 핡심 톡신 λͺ©μ μ§€ IP") for i, kv := range sortMap(sysTargetIps) { if i >= 5 { break } maxIo := sysTargetIpsMaxIO[kv.Key] addBullet(fmt.Sprintf("%s (접속 λΉˆλ„: %d회 | 졜고 νŠΈλž˜ν”½: %.1f MB/s)", kv.Key, kv.Value, maxIo)) } if len(sysTargetIps) == 0 { addBullet("ν•΄λ‹Ή 원인 μ—†μŒ") } addText("") addBoldText("λ§Œμ„±μ  응닡 μ—†μŒ(Hang) λ°œμƒ μ• ν”Œλ¦¬μΌ€μ΄μ…˜") for i, kv := range sortMap(hungCounts) { if i >= 5 { break } addBullet(fmt.Sprintf("%s%s (λΉˆλ„: %d회)", kv.Key, getProcessTag(kv.Key), kv.Value)) } if len(hungCounts) == 0 { addBullet("ν•΄λ‹Ή 원인 μ—†μŒ") } addText("") // --- Detailed Logs --- addH2("2. μ‹œκ°„λŒ€λ³„ 상세 이상 μ§•ν›„ λ°œμƒ 이λ ₯ (Chronological Log)") if len(details) == 0 { addText("기둝된 이상 μ§•ν›„κ°€ μ—†μŠ΅λ‹ˆλ‹€.") addText("") } else { limit := len(details) if limit > 100 { limit = 100 } // λ„ˆλ¬΄ κΈΈμ–΄μ§€λŠ” 것 λ°©μ§€ for i := 0; i < limit; i++ { d := details[i] addBoldText(d.Category) for _, c := range d.Content { addBullet(c) } addText("") } if len(details) > 100 { addText(fmt.Sprintf("... (μƒλž΅λ¨: 총 %d건의 이벀트 쀑 μ΅œμ‹  100건만 좜λ ₯)", len(details))) } } addH2("3. ETW (.etl) 컀널 덀프 μ •λ°€ 뢄석 κ²°κ³Ό") var etlFiles []string if *etlPath != "" { etlFiles = append(etlFiles, *etlPath) } else { localFiles, _ := filepath.Glob("*.etl") etlFiles = append(etlFiles, localFiles...) tempFiles, _ := filepath.Glob("C:\\temp\\*.etl") etlFiles = append(etlFiles, tempFiles...) } if len(etlFiles) > 0 { for _, file := range etlFiles { sysMap := parseETL(file) addBoldText(fmt.Sprintf("πŸ“„ 뢄석 파일: %s", filepath.Base(file))) if len(sysMap) > 0 { addText("컀널 덀프 파일 λ‚΄μ—μ„œ κ°€μž₯ λ§Žμ€ μΈν„°λŸ½νŠΈ 및 파일 검사λ₯Ό μœ λ°œν•œ μ„œλ“œνŒŒν‹° 컀널 λ“œλΌμ΄λ²„(.sys) λž­ν‚Ήμž…λ‹ˆλ‹€.") for i, kv := range sortMap(sysMap) { if i >= 10 { break } if isSecDriver(kv.Key) { addRedBullet(fmt.Sprintf("%dμœ„: %s (λΉˆλ„: %d) 🚨[λ³΄μ•ˆ μ†”λ£¨μ…˜ 컀널 λ“œλΌμ΄λ²„ 적발]", i+1, kv.Key, kv.Value)) } else { addBullet(fmt.Sprintf("%dμœ„: %s (λΉˆλ„: %d)", i+1, kv.Key, kv.Value)) } } addText("") } else { addText("μ„œλ“œνŒŒν‹° λ“œλΌμ΄λ²„ 정보λ₯Ό μΆ”μΆœν•˜μ§€ λͺ»ν–ˆμŠ΅λ‹ˆλ‹€.") } } } else { addText("뢄석할 .etl 컀널 덀프 파일이 μ—†μŠ΅λ‹ˆλ‹€.") } err = f.Save(reportDocx) if err != nil { log.Fatalf("DOCX 파일 μ €μž₯ μ‹€νŒ¨: %v", err) } 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', '%s' λ¬Έμ„œκ°€ μƒμ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€.\n", reportDocx, reportMd, reportHtml) fmt.Printf("==================================================\n") } func parseETL(etlPath string) map[string]int { sysCounts := make(map[string]int) dumpFile := "etl_dump.xml" cmd := exec.Command("tracerpt.exe", etlPath, "-o", dumpFile, "-of", "XML", "-y") cmd.Run() data, err := ioutil.ReadFile(dumpFile) if err != nil { return sysCounts } re := regexp.MustCompile(`(?i)([a-zA-Z0-9_-]+\.sys)`) matches := re.FindAllString(string(data), -1) ignoreList := map[string]bool{ "ntoskrnl.sys": true, "ndis.sys": true, "tcpip.sys": true, "fltmgr.sys": true, "wof.sys": true, "ntfs.sys": true, "dxgkrnl.sys": true, "netbt.sys": true, } for _, match := range matches { match = strings.ToLower(match) if !ignoreList[match] { sysCounts[match]++ } } os.Remove(dumpFile) os.Remove("summary.txt") return sysCounts }