From 76d1161ef629710b5d3ce49275ba3de388358802 Mon Sep 17 00:00:00 2001 From: Asish Kumar Date: Tue, 16 Sep 2025 10:23:38 +0000 Subject: [PATCH 1/6] fix: debug logs Signed-off-by: Asish Kumar --- keploy/keploy.go | 84 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 14 deletions(-) diff --git a/keploy/keploy.go b/keploy/keploy.go index 1bca4dd..57986c2 100644 --- a/keploy/keploy.go +++ b/keploy/keploy.go @@ -86,81 +86,97 @@ func handleControlRequest(conn net.Conn) { command, err := bufio.NewReader(conn).ReadString('\n') if err != nil { - log.Printf("[Agent] Error reading command: %v", err) + log.Printf("[Agent-Debug] Error reading command: %v", err) return } + log.Printf("[Agent-Debug] Received raw command: '%s'", strings.TrimSpace(command)) // Split the command into action and testID parts := strings.SplitN(strings.TrimSpace(command), " ", 2) if len(parts) != 2 { - log.Printf("[Agent] Invalid command format: '%s'", command) + log.Printf("[Agent-Debug] Invalid command format: '%s'", command) return } action, id := parts[0], parts[1] + log.Printf("[Agent-Debug] Parsed command. Action: '%s', ID: '%s'", action, id) controlMu.Lock() defer controlMu.Unlock() switch action { case "START": + log.Printf("[Agent-Debug] Handling START command for test ID: '%s'", id) currentTestID = id err := coverage.ClearCounters() if err != nil { - log.Printf("[Agent] Error clearing coverage counters: %v", err) + log.Printf("[Agent-Debug] Error clearing coverage counters: %v", err) + } else { + log.Printf("[Agent-Debug] Successfully cleared coverage counters for test ID: '%s'", id) } case "END": + log.Printf("[Agent-Debug] Handling END command for test ID: '%s'", id) if currentTestID != id { - log.Printf("[Agent] Warning: Mismatched END command. Expected '%s', got '%s'. Skipping coverage report to avoid inconsistent state.", currentTestID, id) + log.Printf("[Agent-Debug] Warning: Mismatched END command. Expected '%s', got '%s'. Skipping coverage report to avoid inconsistent state.", currentTestID, id) return } err := reportCoverage(id) if err != nil { log.Printf("[Agent] 🚨 Error reporting coverage for test %s: %v", id, err) + } else { + log.Printf("[Agent-Debug] Successfully initiated coverage report for test ID: '%s'", id) } // Reset the currentTestID to an empty string to indicate that no test is currently being recorded. + log.Printf("[Agent-Debug] Resetting currentTestID from '%s' to empty.", currentTestID) currentTestID = "" _, err = conn.Write([]byte("ACK\n")) if err != nil { - log.Printf("[Agent] Error sending ACK to controller: %v", err) + log.Printf("[Agent-Debug] Error sending ACK to controller: %v", err) } default: - log.Printf("[Agent] Unrecognized command: %s", action) + log.Printf("[Agent-Debug] Unrecognized command: %s", action) } } // reportCoverage dumps, processes, and sends the coverage data. func reportCoverage(testID string) error { + log.Printf("[Agent-Debug] Starting reportCoverage for testID: '%s'", testID) // Only take the part before the first slash, // e.g. "test-2" from "test-set-0/test-2" parts := strings.SplitN(testID, "/", 2) baseID := parts[1] + log.Printf("[Agent-Debug] Extracted baseID: '%s'", baseID) // Create a temporary directory to store the coverage data. tempDir, err := os.MkdirTemp("", fmt.Sprintf("keploy-coverage-%s-", baseID)) if err != nil { return fmt.Errorf("failed to create temp dir: %w", err) } - defer func() { - if err := os.RemoveAll(tempDir); err != nil { - log.Printf("[Agent] Error removing temp dir: %v", err) - } - }() + log.Printf("[Agent-Debug] Created temporary directory for coverage data: %s", tempDir) + // defer func() { + // if err := os.RemoveAll(tempDir); err != nil { + // log.Printf("[Agent] Error removing temp dir: %v", err) + // } + // }() err = coverage.WriteCountersDir(tempDir) if err != nil { return fmt.Errorf("failed to write coverage counters. Ensure the application was built with '-cover -covermode=atomic'. Original error: %w", err) } + log.Printf("[Agent-Debug] Successfully wrote coverage counters to %s", tempDir) err = coverage.WriteMetaDir(tempDir) if err != nil { return fmt.Errorf("failed to write meta dir: %w", err) } + log.Printf("[Agent-Debug] Successfully wrote meta data to %s", tempDir) + log.Printf("[Agent-Debug] Processing coverage profiles from directory: %s", tempDir) processedData, err := processCoverageProfilesUsingCovdata(tempDir) if err != nil { return fmt.Errorf("failed to process coverage profiles: %w", err) } + log.Printf("[Agent-Debug] Finished processing coverage profiles. Found coverage for %d files.", len(processedData)) if len(processedData) == 0 { log.Printf("[Agent-Warning] No covered lines were found for test %s. The report will be empty.", testID) @@ -175,8 +191,16 @@ func reportCoverage(testID string) error { if err != nil { return fmt.Errorf("failed to marshal coverage data to JSON: %w", err) } + log.Printf("[Agent-Debug] Marshalled JSON payload of size %d bytes for testID: '%s'", len(jsonData), testID) - return sendToSocket(jsonData) + log.Printf("[Agent-Debug] Sending coverage data to socket for testID: '%s'", testID) + err = sendToSocket(jsonData) + if err != nil { + log.Printf("[Agent-Debug] Error sending data to socket: %v", err) + return err + } + log.Printf("[Agent-Debug] Successfully sent coverage data to socket for testID: '%s'", testID) + return nil } // sendToSocket connects to the Keploy data socket and writes the JSON payload. @@ -198,15 +222,18 @@ func sendToSocket(data []byte) error { // processCoverageProfilesUsingCovdata uses the covdata tool to convert binary coverage data to text format // and then processes it using the standard cover package. func processCoverageProfilesUsingCovdata(dir string) (map[string][]int, error) { + log.Printf("[Agent-Debug] processCoverageProfilesUsingCovdata called for directory: '%s'", dir) // Create a temporary file for the text format output textFile, err := os.CreateTemp("", "coverage-*.txt") if err != nil { return nil, fmt.Errorf("failed to create temp file for text coverage: %w", err) } + log.Printf("[Agent-Debug] Created temporary text file: '%s'", textFile.Name()) defer func() { if err := os.Remove(textFile.Name()); err != nil { log.Printf("[Agent] Error removing temp file: %v", err) } + log.Printf("[Agent-Debug] Removed temporary text file: '%s'", textFile.Name()) }() defer func() { @@ -219,58 +246,83 @@ func processCoverageProfilesUsingCovdata(dir string) (map[string][]int, error) { cmd := exec.Command("go", "tool", "covdata", "textfmt", "-i="+dir, "-o="+textFile.Name()) var stderr bytes.Buffer cmd.Stderr = &stderr + log.Printf("[Agent-Debug] Executing command: %s", cmd.String()) err = cmd.Run() if err != nil { return nil, fmt.Errorf("failed to convert coverage data to text format: %w\nStderr: %s", err, stderr.String()) } + log.Printf("[Agent-Debug] Successfully executed 'go tool covdata'.") + + // Check the size of the output file + fileInfo, err := textFile.Stat() + if err != nil { + log.Printf("[Agent-Debug] Could not stat temporary text file '%s': %v", textFile.Name(), err) + } else { + log.Printf("[Agent-Debug] Temporary text file '%s' has size: %d bytes.", textFile.Name(), fileInfo.Size()) + if fileInfo.Size() == 0 { + log.Printf("[Agent-Warning] The 'go tool covdata' command produced an empty output file. This likely means no coverage counters were set during the test run.") + } + } // Get the module path (e.g., "your/module/path") to resolve file paths correctly. modulePathCmd := exec.Command("go", "list", "-m") var stderrModPath bytes.Buffer modulePathCmd.Stderr = &stderrModPath + log.Printf("[Agent-Debug] Executing command: %s", modulePathCmd.String()) modulePathBytes, err := modulePathCmd.Output() if err != nil { return nil, fmt.Errorf("failed to get module path with 'go list -m': %w\nStderr: %s", err, stderrModPath.String()) } modulePath := strings.TrimSpace(string(modulePathBytes)) + log.Printf("[Agent-Debug] Detected module path: '%s'", modulePath) // Get the module's root directory on the filesystem. moduleDirCmd := exec.Command("go", "list", "-m", "-f", "{{.Dir}}") var stderrModDir bytes.Buffer moduleDirCmd.Stderr = &stderrModDir + log.Printf("[Agent-Debug] Executing command: %s", moduleDirCmd.String()) moduleDirBytes, err := moduleDirCmd.Output() if err != nil { return nil, fmt.Errorf("failed to get module directory with 'go list -m -f {{.Dir}}': %w\nStderr: %s", err, stderrModDir.String()) } moduleDir := strings.TrimSpace(string(moduleDirBytes)) + log.Printf("[Agent-Debug] Detected module directory: '%s'", moduleDir) // Parse the text format using the standard cover package. + log.Printf("[Agent-Debug] Parsing text coverage profile from: '%s'", textFile.Name()) profiles, err := cover.ParseProfiles(textFile.Name()) if err != nil { return nil, fmt.Errorf("failed to parse text coverage profile: %w", err) } + log.Printf("[Agent-Debug] Parsed %d profiles from the coverage file.", len(profiles)) executedLinesByFile := make(map[string][]int) - for _, profile := range profiles { + for i, profile := range profiles { + log.Printf("[Agent-Debug] Processing profile #%d for file: '%s'", i+1, profile.FileName) var absolutePath string if strings.HasPrefix(profile.FileName, modulePath) { relativePath := strings.TrimPrefix(profile.FileName, modulePath) absolutePath = filepath.Join(moduleDir, relativePath) + log.Printf("[Agent-Debug] Profile #%d: Matched module path. Relative path: '%s', Absolute path: '%s'", i+1, relativePath, absolutePath) } else if !filepath.IsAbs(profile.FileName) { + log.Printf("[Agent-Debug] Profile #%d: Skipping file '%s' because it is not an absolute path and does not match the module path.", i+1, profile.FileName) continue } else { absolutePath = profile.FileName + log.Printf("[Agent-Debug] Profile #%d: Using existing absolute path: '%s'", i+1, absolutePath) } lineSet := make(map[int]bool) + log.Printf("[Agent-Debug] Profile #%d has %d blocks to process.", i+1, len(profile.Blocks)) // For each block in the profile, if the count is greater than 0, add the lines to the map. - for _, block := range profile.Blocks { + for j, block := range profile.Blocks { if block.Count <= 0 { continue } + log.Printf("[Agent-Debug] Profile #%d, Block #%d: Count is %d. Processing lines %d to %d.", i+1, j+1, block.Count, block.StartLine, block.EndLine) for line := block.StartLine; line <= block.EndLine; line++ { lineSet[line] = true } @@ -284,8 +336,12 @@ func processCoverageProfilesUsingCovdata(dir string) (map[string][]int, error) { } sort.Ints(lines) executedLinesByFile[absolutePath] = lines + log.Printf("[Agent-Debug] Profile #%d: Found %d executed lines for file '%s'.", i+1, len(lines), absolutePath) + } else { + log.Printf("[Agent-Debug] Profile #%d: No executed lines found for file '%s' after processing all blocks.", i+1, absolutePath) } } + log.Printf("[Agent-Debug] Final processed data contains coverage for %d files.", len(executedLinesByFile)) return executedLinesByFile, nil } From f04140995c93dcb24a1f81a614396fe8ad48048d Mon Sep 17 00:00:00 2001 From: Asish Kumar Date: Tue, 16 Sep 2025 11:02:51 +0000 Subject: [PATCH 2/6] fix: more logs Signed-off-by: Asish Kumar --- keploy/keploy.go | 304 ++++++++++++++++++++++++++++------------------- 1 file changed, 182 insertions(+), 122 deletions(-) diff --git a/keploy/keploy.go b/keploy/keploy.go index 57986c2..438e0a4 100644 --- a/keploy/keploy.go +++ b/keploy/keploy.go @@ -21,6 +21,7 @@ import ( "sort" "strings" "sync" + "time" "golang.org/x/tools/cover" ) @@ -41,15 +42,17 @@ var ( // init starts the background control server that listens for commands from the Keploy test runner. func init() { + log.Printf("[Agent] Init: starting control server goroutine. PID=%d, PPID=%d, CWD=%s", os.Getpid(), os.Getppid(), mustGetwd()) go startControlServer() } // startControlServer sets up and runs the Unix socket server that listens for commands from Keploy. func startControlServer() { - err := os.RemoveAll(controlSocketPath) - if err != nil { - log.Printf("[Agent] Failed to remove old control socket: %v", err) - return + log.Printf("[Agent] Control: preparing socket at %s", controlSocketPath) + + if err := os.RemoveAll(controlSocketPath); err != nil { + log.Printf("[Agent] Control: failed to remove old control socket: %v", err) + // not returning; try to continue } ln, err := net.Listen("unix", controlSocketPath) @@ -58,20 +61,25 @@ func startControlServer() { return } defer func() { + log.Printf("[Agent] Control: shutting down listener") if err := ln.Close(); err != nil { - log.Printf("[Agent] Error closing control server: %v", err) + log.Printf("[Agent] Control: error closing control server: %v", err) } }() + log.Printf("[Agent] Control: listening on %s", controlSocketPath) + for { conn, err := ln.Accept() if err != nil { if strings.Contains(err.Error(), "use of closed network connection") { + log.Printf("[Agent] Control: listener closed, stopping accept loop") break } - log.Printf("[Agent] Error accepting connection: %v", err) + log.Printf("[Agent] Control: error accepting connection: %v", err) continue } + log.Printf("[Agent] Control: accepted connection from %T", conn.RemoteAddr()) go handleControlRequest(conn) } } @@ -80,165 +88,192 @@ func startControlServer() { func handleControlRequest(conn net.Conn) { defer func() { if err := conn.Close(); err != nil { - log.Printf("[Agent] Error closing connection: %v", err) + log.Printf("[Agent] Control: error closing connection: %v", err) } }() - command, err := bufio.NewReader(conn).ReadString('\n') + reader := bufio.NewReader(conn) + command, err := reader.ReadString('\n') if err != nil { - log.Printf("[Agent-Debug] Error reading command: %v", err) + log.Printf("[Agent] Control: error reading command: %v", err) return } - log.Printf("[Agent-Debug] Received raw command: '%s'", strings.TrimSpace(command)) + command = strings.TrimSpace(command) + log.Printf("[Agent] Control: raw command received: %q", command) // Split the command into action and testID - parts := strings.SplitN(strings.TrimSpace(command), " ", 2) + parts := strings.SplitN(command, " ", 2) if len(parts) != 2 { - log.Printf("[Agent-Debug] Invalid command format: '%s'", command) + log.Printf("[Agent] Control: invalid command format: %q", command) return } action, id := parts[0], parts[1] - log.Printf("[Agent-Debug] Parsed command. Action: '%s', ID: '%s'", action, id) + log.Printf("[Agent] Control: action=%q testID=%q", action, id) controlMu.Lock() defer controlMu.Unlock() switch action { case "START": - log.Printf("[Agent-Debug] Handling START command for test ID: '%s'", id) + log.Printf("[Agent] Control: START for testID=%q (prev=%q). Clearing coverage counters...", id, currentTestID) currentTestID = id - err := coverage.ClearCounters() - if err != nil { - log.Printf("[Agent-Debug] Error clearing coverage counters: %v", err) + if err := coverage.ClearCounters(); err != nil { + log.Printf("[Agent] Control: error clearing coverage counters: %v", err) } else { - log.Printf("[Agent-Debug] Successfully cleared coverage counters for test ID: '%s'", id) + log.Printf("[Agent] Control: coverage counters cleared successfully") } case "END": - log.Printf("[Agent-Debug] Handling END command for test ID: '%s'", id) + log.Printf("[Agent] Control: END for testID=%q (current=%q).", id, currentTestID) if currentTestID != id { - log.Printf("[Agent-Debug] Warning: Mismatched END command. Expected '%s', got '%s'. Skipping coverage report to avoid inconsistent state.", currentTestID, id) + log.Printf("[Agent] Control: WARNING mismatch END. Expected=%q, Got=%q. Skipping coverage report.", currentTestID, id) return } - err := reportCoverage(id) - if err != nil { + if err := reportCoverage(id); err != nil { log.Printf("[Agent] 🚨 Error reporting coverage for test %s: %v", id, err) } else { - log.Printf("[Agent-Debug] Successfully initiated coverage report for test ID: '%s'", id) + log.Printf("[Agent] Control: reportCoverage done for %q", id) } - // Reset the currentTestID to an empty string to indicate that no test is currently being recorded. - log.Printf("[Agent-Debug] Resetting currentTestID from '%s' to empty.", currentTestID) currentTestID = "" - _, err = conn.Write([]byte("ACK\n")) - if err != nil { - log.Printf("[Agent-Debug] Error sending ACK to controller: %v", err) + if _, err := conn.Write([]byte("ACK\n")); err != nil { + log.Printf("[Agent] Control: error sending ACK to controller: %v", err) + } else { + log.Printf("[Agent] Control: ACK sent to controller") } default: - log.Printf("[Agent-Debug] Unrecognized command: %s", action) + log.Printf("[Agent] Control: unrecognized command: %s", action) } } // reportCoverage dumps, processes, and sends the coverage data. func reportCoverage(testID string) error { - log.Printf("[Agent-Debug] Starting reportCoverage for testID: '%s'", testID) - // Only take the part before the first slash, - // e.g. "test-2" from "test-set-0/test-2" - parts := strings.SplitN(testID, "/", 2) - baseID := parts[1] - log.Printf("[Agent-Debug] Extracted baseID: '%s'", baseID) + start := time.Now() + log.Printf("[Agent] Report: starting for testID=%q", testID) + + // Derive a stable baseID from the last path segment to avoid index errors and to work with/without slashes. + // Examples: + // - "test-set-0/test-2" -> "test-2" + // - "test-2" -> "test-2" + // - "suite/a/b/test-13" -> "test-13" + segments := strings.Split(testID, "/") + baseID := segments[len(segments)-1] + log.Printf("[Agent] Report: derived baseID=%q from testID=%q (segments=%v)", baseID, testID, segments) // Create a temporary directory to store the coverage data. tempDir, err := os.MkdirTemp("", fmt.Sprintf("keploy-coverage-%s-", baseID)) if err != nil { - return fmt.Errorf("failed to create temp dir: %w", err) + return fmt.Errorf("report: failed to create temp dir: %w", err) } - log.Printf("[Agent-Debug] Created temporary directory for coverage data: %s", tempDir) - // defer func() { - // if err := os.RemoveAll(tempDir); err != nil { - // log.Printf("[Agent] Error removing temp dir: %v", err) - // } - // }() - - err = coverage.WriteCountersDir(tempDir) - if err != nil { - return fmt.Errorf("failed to write coverage counters. Ensure the application was built with '-cover -covermode=atomic'. Original error: %w", err) + log.Printf("[Agent] Report: tempDir=%s", tempDir) + + // Try to write binary counters and meta. + if err := coverage.WriteCountersDir(tempDir); err != nil { + return fmt.Errorf("report: failed to write coverage counters. Ensure the app was built with '-cover -covermode=atomic'. original: %w", err) } - log.Printf("[Agent-Debug] Successfully wrote coverage counters to %s", tempDir) + log.Printf("[Agent] Report: WriteCountersDir OK") - err = coverage.WriteMetaDir(tempDir) - if err != nil { - return fmt.Errorf("failed to write meta dir: %w", err) + if err := coverage.WriteMetaDir(tempDir); err != nil { + return fmt.Errorf("report: failed to write meta dir: %w", err) } - log.Printf("[Agent-Debug] Successfully wrote meta data to %s", tempDir) + log.Printf("[Agent] Report: WriteMetaDir OK") - log.Printf("[Agent-Debug] Processing coverage profiles from directory: %s", tempDir) - processedData, err := processCoverageProfilesUsingCovdata(tempDir) + // Quick diagnostics: list what got written + listed := listDir(tempDir) + log.Printf("[Agent] Report: tempDir listing -> %d entries: %v", len(listed), listed) + + // Process with covdata and then ParseProfiles + executed, err := processCoverageProfilesUsingCovdata(tempDir) if err != nil { - return fmt.Errorf("failed to process coverage profiles: %w", err) + return fmt.Errorf("report: failed to process coverage profiles: %w", err) } - log.Printf("[Agent-Debug] Finished processing coverage profiles. Found coverage for %d files.", len(processedData)) - if len(processedData) == 0 { - log.Printf("[Agent-Warning] No covered lines were found for test %s. The report will be empty.", testID) + // Summarize results + totalFiles := 0 + totalLines := 0 + for f, lines := range executed { + totalFiles++ + totalLines += len(lines) + if len(lines) == 0 { + log.Printf("[Agent] Report: file=%s has 0 covered lines (unexpected since it’s present)", f) + } else { + // For very verbose mode, dump first few lines only to keep logs manageable + preview := lines + if len(lines) > 20 { + preview = lines[:20] + } + log.Printf("[Agent] Report: file=%s coveredLines=%d preview(first<=20)=%v", f, len(lines), preview) + } + } + + if totalLines == 0 { + log.Printf("[Agent-Warning] No covered lines were found for test %s. The report will be empty. (files=%d)", testID, totalFiles) } payload := map[string]interface{}{ "id": testID, - "executedLinesByFile": processedData, + "executedLinesByFile": executed, } jsonData, err := json.Marshal(payload) if err != nil { - return fmt.Errorf("failed to marshal coverage data to JSON: %w", err) + return fmt.Errorf("report: failed to marshal coverage data to JSON: %w", err) } - log.Printf("[Agent-Debug] Marshalled JSON payload of size %d bytes for testID: '%s'", len(jsonData), testID) + log.Printf("[Agent] Report: payload bytes=%d, files=%d, totalCoveredLines=%d", len(jsonData), totalFiles, totalLines) - log.Printf("[Agent-Debug] Sending coverage data to socket for testID: '%s'", testID) - err = sendToSocket(jsonData) - if err != nil { - log.Printf("[Agent-Debug] Error sending data to socket: %v", err) - return err + // Send to data socket + if err := sendToSocket(jsonData); err != nil { + return fmt.Errorf("report: failed sending to data socket: %w", err) } - log.Printf("[Agent-Debug] Successfully sent coverage data to socket for testID: '%s'", testID) + log.Printf("[Agent] Report: sendToSocket OK in %s", time.Since(start)) return nil } // sendToSocket connects to the Keploy data socket and writes the JSON payload. func sendToSocket(data []byte) error { + log.Printf("[Agent] DataSock: dialing %s", dataSocketPath) conn, err := net.Dial("unix", dataSocketPath) if err != nil { return fmt.Errorf("could not connect to keploy data socket at %s: %w", dataSocketPath, err) } defer func() { + log.Printf("[Agent] DataSock: closing connection") if err := conn.Close(); err != nil { - log.Printf("[Agent] Error closing connection: %v", err) + log.Printf("[Agent] DataSock: error closing connection: %v", err) } }() - _, err = conn.Write(data) + n, err := conn.Write(data) + log.Printf("[Agent] DataSock: wrote %d bytes (err=%v)", n, err) return err } // processCoverageProfilesUsingCovdata uses the covdata tool to convert binary coverage data to text format // and then processes it using the standard cover package. func processCoverageProfilesUsingCovdata(dir string) (map[string][]int, error) { - log.Printf("[Agent-Debug] processCoverageProfilesUsingCovdata called for directory: '%s'", dir) + log.Printf("[Agent] Covdata: begin. dir=%s", dir) + + // Log go version for diagnostics + if out, err := exec.Command("go", "version").CombinedOutput(); err != nil { + log.Printf("[Agent] Covdata: 'go version' failed: %v (out=%q)", err, string(out)) + } else { + log.Printf("[Agent] Covdata: %s", strings.TrimSpace(string(out))) + } + // Create a temporary file for the text format output textFile, err := os.CreateTemp("", "coverage-*.txt") if err != nil { - return nil, fmt.Errorf("failed to create temp file for text coverage: %w", err) + return nil, fmt.Errorf("covdata: failed to create temp file for text coverage: %w", err) } - log.Printf("[Agent-Debug] Created temporary text file: '%s'", textFile.Name()) - defer func() { - if err := os.Remove(textFile.Name()); err != nil { - log.Printf("[Agent] Error removing temp file: %v", err) - } - log.Printf("[Agent-Debug] Removed temporary text file: '%s'", textFile.Name()) - }() + log.Printf("[Agent] Covdata: text output file=%s", textFile.Name()) defer func() { + log.Printf("[Agent] Covdata: closing text file") if err := textFile.Close(); err != nil { - log.Printf("[Agent] Error closing temp file: %v", err) + log.Printf("[Agent] Covdata: error closing temp file: %v", err) + } + log.Printf("[Agent] Covdata: removing text file %s", textFile.Name()) + if err := os.Remove(textFile.Name()); err != nil { + log.Printf("[Agent] Covdata: error removing temp file: %v", err) } }() @@ -246,102 +281,127 @@ func processCoverageProfilesUsingCovdata(dir string) (map[string][]int, error) { cmd := exec.Command("go", "tool", "covdata", "textfmt", "-i="+dir, "-o="+textFile.Name()) var stderr bytes.Buffer cmd.Stderr = &stderr - log.Printf("[Agent-Debug] Executing command: %s", cmd.String()) - err = cmd.Run() - if err != nil { - return nil, fmt.Errorf("failed to convert coverage data to text format: %w\nStderr: %s", err, stderr.String()) + log.Printf("[Agent] Covdata: running %q", strings.Join(cmd.Args, " ")) + if err := cmd.Run(); err != nil { + return nil, fmt.Errorf("covdata: failed to convert coverage data to text format: %w; stderr: %s", err, stderr.String()) } - log.Printf("[Agent-Debug] Successfully executed 'go tool covdata'.") - - // Check the size of the output file - fileInfo, err := textFile.Stat() - if err != nil { - log.Printf("[Agent-Debug] Could not stat temporary text file '%s': %v", textFile.Name(), err) + if s := strings.TrimSpace(stderr.String()); s != "" { + log.Printf("[Agent] Covdata: warnings/stderr: %s", s) } else { - log.Printf("[Agent-Debug] Temporary text file '%s' has size: %d bytes.", textFile.Name(), fileInfo.Size()) - if fileInfo.Size() == 0 { - log.Printf("[Agent-Warning] The 'go tool covdata' command produced an empty output file. This likely means no coverage counters were set during the test run.") - } + log.Printf("[Agent] Covdata: textfmt OK; stderr empty") } // Get the module path (e.g., "your/module/path") to resolve file paths correctly. modulePathCmd := exec.Command("go", "list", "-m") var stderrModPath bytes.Buffer modulePathCmd.Stderr = &stderrModPath - log.Printf("[Agent-Debug] Executing command: %s", modulePathCmd.String()) modulePathBytes, err := modulePathCmd.Output() if err != nil { - return nil, fmt.Errorf("failed to get module path with 'go list -m': %w\nStderr: %s", err, stderrModPath.String()) + return nil, fmt.Errorf("covdata: failed to get module path with 'go list -m': %w; stderr: %s", err, stderrModPath.String()) } modulePath := strings.TrimSpace(string(modulePathBytes)) - log.Printf("[Agent-Debug] Detected module path: '%s'", modulePath) + log.Printf("[Agent] Covdata: modulePath=%q", modulePath) // Get the module's root directory on the filesystem. moduleDirCmd := exec.Command("go", "list", "-m", "-f", "{{.Dir}}") var stderrModDir bytes.Buffer moduleDirCmd.Stderr = &stderrModDir - log.Printf("[Agent-Debug] Executing command: %s", moduleDirCmd.String()) moduleDirBytes, err := moduleDirCmd.Output() if err != nil { - return nil, fmt.Errorf("failed to get module directory with 'go list -m -f {{.Dir}}': %w\nStderr: %s", err, stderrModDir.String()) + return nil, fmt.Errorf("covdata: failed to get module directory with 'go list -m -f {{.Dir}}': %w; stderr: %s", err, stderrModDir.String()) } moduleDir := strings.TrimSpace(string(moduleDirBytes)) - log.Printf("[Agent-Debug] Detected module directory: '%s'", moduleDir) + log.Printf("[Agent] Covdata: moduleDir=%q", moduleDir) // Parse the text format using the standard cover package. - log.Printf("[Agent-Debug] Parsing text coverage profile from: '%s'", textFile.Name()) + log.Printf("[Agent] Covdata: parsing profiles from %s", textFile.Name()) profiles, err := cover.ParseProfiles(textFile.Name()) if err != nil { - return nil, fmt.Errorf("failed to parse text coverage profile: %w", err) + return nil, fmt.Errorf("covdata: failed to parse text coverage profile: %w", err) } - log.Printf("[Agent-Debug] Parsed %d profiles from the coverage file.", len(profiles)) + log.Printf("[Agent] Covdata: parsed %d profiles", len(profiles)) executedLinesByFile := make(map[string][]int) for i, profile := range profiles { - log.Printf("[Agent-Debug] Processing profile #%d for file: '%s'", i+1, profile.FileName) + log.Printf("[Agent] Covdata: profile[%d] fileName=%q blocks=%d", i, profile.FileName, len(profile.Blocks)) + var absolutePath string - if strings.HasPrefix(profile.FileName, modulePath) { + switch { + case strings.HasPrefix(profile.FileName, modulePath): relativePath := strings.TrimPrefix(profile.FileName, modulePath) absolutePath = filepath.Join(moduleDir, relativePath) - log.Printf("[Agent-Debug] Profile #%d: Matched module path. Relative path: '%s', Absolute path: '%s'", i+1, relativePath, absolutePath) - } else if !filepath.IsAbs(profile.FileName) { - log.Printf("[Agent-Debug] Profile #%d: Skipping file '%s' because it is not an absolute path and does not match the module path.", i+1, profile.FileName) + log.Printf("[Agent] Covdata: resolved via modulePath => %s", absolutePath) + case !filepath.IsAbs(profile.FileName): + log.Printf("[Agent] Covdata: skipping non-absolute non-module path file=%q", profile.FileName) continue - } else { + default: absolutePath = profile.FileName - log.Printf("[Agent-Debug] Profile #%d: Using existing absolute path: '%s'", i+1, absolutePath) + log.Printf("[Agent] Covdata: absolute path taken => %s", absolutePath) } lineSet := make(map[int]bool) + totalPositive := 0 - log.Printf("[Agent-Debug] Profile #%d has %d blocks to process.", i+1, len(profile.Blocks)) // For each block in the profile, if the count is greater than 0, add the lines to the map. for j, block := range profile.Blocks { if block.Count <= 0 { + // This block wasn't executed continue } - log.Printf("[Agent-Debug] Profile #%d, Block #%d: Count is %d. Processing lines %d to %d.", i+1, j+1, block.Count, block.StartLine, block.EndLine) + totalPositive++ for line := block.StartLine; line <= block.EndLine; line++ { lineSet[line] = true } + if j < 5 { // limit per-profile spam + log.Printf("[Agent] Covdata: block[%d] start=%d end=%d count=%d", j, block.StartLine, block.EndLine, block.Count) + } } - // If there are any lines executed, add them to the map. - if len(lineSet) > 0 { - lines := make([]int, 0, len(lineSet)) - for line := range lineSet { - lines = append(lines, line) - } - sort.Ints(lines) - executedLinesByFile[absolutePath] = lines - log.Printf("[Agent-Debug] Profile #%d: Found %d executed lines for file '%s'.", i+1, len(lines), absolutePath) - } else { - log.Printf("[Agent-Debug] Profile #%d: No executed lines found for file '%s' after processing all blocks.", i+1, absolutePath) + if len(lineSet) == 0 { + log.Printf("[Agent] Covdata: file=%s has 0 executed lines; positiveBlocks=%d (might indicate counters not flushed or build flags missing)", absolutePath, totalPositive) + continue + } + + lines := make([]int, 0, len(lineSet)) + for line := range lineSet { + lines = append(lines, line) } + sort.Ints(lines) + executedLinesByFile[absolutePath] = lines + log.Printf("[Agent] Covdata: file=%s executedLines=%d", absolutePath, len(lines)) } - log.Printf("[Agent-Debug] Final processed data contains coverage for %d files.", len(executedLinesByFile)) + log.Printf("[Agent] Covdata: executed files=%d", len(executedLinesByFile)) return executedLinesByFile, nil } + +// helpers + +func listDir(dir string) []string { + entries, err := os.ReadDir(dir) + if err != nil { + return []string{fmt.Sprintf("ERR: %v", err)} + } + var out []string + for _, e := range entries { + name := e.Name() + full := filepath.Join(dir, name) + info, err := e.Info() + if err != nil { + out = append(out, fmt.Sprintf("%s (err: %v)", name, err)) + continue + } + out = append(out, fmt.Sprintf("%s size=%d mode=%s", full, info.Size(), info.Mode())) + } + return out +} + +func mustGetwd() string { + wd, err := os.Getwd() + if err != nil { + return fmt.Sprintf("ERR:%v", err) + } + return wd +} From 1ab209c9ddefb35a478a3193a38f1002f699557d Mon Sep 17 00:00:00 2001 From: Asish Kumar Date: Tue, 16 Sep 2025 11:14:19 +0000 Subject: [PATCH 3/6] fix: more logs Signed-off-by: Asish Kumar --- keploy/keploy.go | 304 +++++++++++++++++++---------------------------- 1 file changed, 122 insertions(+), 182 deletions(-) diff --git a/keploy/keploy.go b/keploy/keploy.go index 438e0a4..57986c2 100644 --- a/keploy/keploy.go +++ b/keploy/keploy.go @@ -21,7 +21,6 @@ import ( "sort" "strings" "sync" - "time" "golang.org/x/tools/cover" ) @@ -42,17 +41,15 @@ var ( // init starts the background control server that listens for commands from the Keploy test runner. func init() { - log.Printf("[Agent] Init: starting control server goroutine. PID=%d, PPID=%d, CWD=%s", os.Getpid(), os.Getppid(), mustGetwd()) go startControlServer() } // startControlServer sets up and runs the Unix socket server that listens for commands from Keploy. func startControlServer() { - log.Printf("[Agent] Control: preparing socket at %s", controlSocketPath) - - if err := os.RemoveAll(controlSocketPath); err != nil { - log.Printf("[Agent] Control: failed to remove old control socket: %v", err) - // not returning; try to continue + err := os.RemoveAll(controlSocketPath) + if err != nil { + log.Printf("[Agent] Failed to remove old control socket: %v", err) + return } ln, err := net.Listen("unix", controlSocketPath) @@ -61,25 +58,20 @@ func startControlServer() { return } defer func() { - log.Printf("[Agent] Control: shutting down listener") if err := ln.Close(); err != nil { - log.Printf("[Agent] Control: error closing control server: %v", err) + log.Printf("[Agent] Error closing control server: %v", err) } }() - log.Printf("[Agent] Control: listening on %s", controlSocketPath) - for { conn, err := ln.Accept() if err != nil { if strings.Contains(err.Error(), "use of closed network connection") { - log.Printf("[Agent] Control: listener closed, stopping accept loop") break } - log.Printf("[Agent] Control: error accepting connection: %v", err) + log.Printf("[Agent] Error accepting connection: %v", err) continue } - log.Printf("[Agent] Control: accepted connection from %T", conn.RemoteAddr()) go handleControlRequest(conn) } } @@ -88,192 +80,165 @@ func startControlServer() { func handleControlRequest(conn net.Conn) { defer func() { if err := conn.Close(); err != nil { - log.Printf("[Agent] Control: error closing connection: %v", err) + log.Printf("[Agent] Error closing connection: %v", err) } }() - reader := bufio.NewReader(conn) - command, err := reader.ReadString('\n') + command, err := bufio.NewReader(conn).ReadString('\n') if err != nil { - log.Printf("[Agent] Control: error reading command: %v", err) + log.Printf("[Agent-Debug] Error reading command: %v", err) return } - command = strings.TrimSpace(command) - log.Printf("[Agent] Control: raw command received: %q", command) + log.Printf("[Agent-Debug] Received raw command: '%s'", strings.TrimSpace(command)) // Split the command into action and testID - parts := strings.SplitN(command, " ", 2) + parts := strings.SplitN(strings.TrimSpace(command), " ", 2) if len(parts) != 2 { - log.Printf("[Agent] Control: invalid command format: %q", command) + log.Printf("[Agent-Debug] Invalid command format: '%s'", command) return } action, id := parts[0], parts[1] - log.Printf("[Agent] Control: action=%q testID=%q", action, id) + log.Printf("[Agent-Debug] Parsed command. Action: '%s', ID: '%s'", action, id) controlMu.Lock() defer controlMu.Unlock() switch action { case "START": - log.Printf("[Agent] Control: START for testID=%q (prev=%q). Clearing coverage counters...", id, currentTestID) + log.Printf("[Agent-Debug] Handling START command for test ID: '%s'", id) currentTestID = id - if err := coverage.ClearCounters(); err != nil { - log.Printf("[Agent] Control: error clearing coverage counters: %v", err) + err := coverage.ClearCounters() + if err != nil { + log.Printf("[Agent-Debug] Error clearing coverage counters: %v", err) } else { - log.Printf("[Agent] Control: coverage counters cleared successfully") + log.Printf("[Agent-Debug] Successfully cleared coverage counters for test ID: '%s'", id) } case "END": - log.Printf("[Agent] Control: END for testID=%q (current=%q).", id, currentTestID) + log.Printf("[Agent-Debug] Handling END command for test ID: '%s'", id) if currentTestID != id { - log.Printf("[Agent] Control: WARNING mismatch END. Expected=%q, Got=%q. Skipping coverage report.", currentTestID, id) + log.Printf("[Agent-Debug] Warning: Mismatched END command. Expected '%s', got '%s'. Skipping coverage report to avoid inconsistent state.", currentTestID, id) return } - if err := reportCoverage(id); err != nil { + err := reportCoverage(id) + if err != nil { log.Printf("[Agent] 🚨 Error reporting coverage for test %s: %v", id, err) } else { - log.Printf("[Agent] Control: reportCoverage done for %q", id) + log.Printf("[Agent-Debug] Successfully initiated coverage report for test ID: '%s'", id) } + // Reset the currentTestID to an empty string to indicate that no test is currently being recorded. + log.Printf("[Agent-Debug] Resetting currentTestID from '%s' to empty.", currentTestID) currentTestID = "" - if _, err := conn.Write([]byte("ACK\n")); err != nil { - log.Printf("[Agent] Control: error sending ACK to controller: %v", err) - } else { - log.Printf("[Agent] Control: ACK sent to controller") + _, err = conn.Write([]byte("ACK\n")) + if err != nil { + log.Printf("[Agent-Debug] Error sending ACK to controller: %v", err) } default: - log.Printf("[Agent] Control: unrecognized command: %s", action) + log.Printf("[Agent-Debug] Unrecognized command: %s", action) } } // reportCoverage dumps, processes, and sends the coverage data. func reportCoverage(testID string) error { - start := time.Now() - log.Printf("[Agent] Report: starting for testID=%q", testID) - - // Derive a stable baseID from the last path segment to avoid index errors and to work with/without slashes. - // Examples: - // - "test-set-0/test-2" -> "test-2" - // - "test-2" -> "test-2" - // - "suite/a/b/test-13" -> "test-13" - segments := strings.Split(testID, "/") - baseID := segments[len(segments)-1] - log.Printf("[Agent] Report: derived baseID=%q from testID=%q (segments=%v)", baseID, testID, segments) + log.Printf("[Agent-Debug] Starting reportCoverage for testID: '%s'", testID) + // Only take the part before the first slash, + // e.g. "test-2" from "test-set-0/test-2" + parts := strings.SplitN(testID, "/", 2) + baseID := parts[1] + log.Printf("[Agent-Debug] Extracted baseID: '%s'", baseID) // Create a temporary directory to store the coverage data. tempDir, err := os.MkdirTemp("", fmt.Sprintf("keploy-coverage-%s-", baseID)) if err != nil { - return fmt.Errorf("report: failed to create temp dir: %w", err) - } - log.Printf("[Agent] Report: tempDir=%s", tempDir) - - // Try to write binary counters and meta. - if err := coverage.WriteCountersDir(tempDir); err != nil { - return fmt.Errorf("report: failed to write coverage counters. Ensure the app was built with '-cover -covermode=atomic'. original: %w", err) + return fmt.Errorf("failed to create temp dir: %w", err) } - log.Printf("[Agent] Report: WriteCountersDir OK") - - if err := coverage.WriteMetaDir(tempDir); err != nil { - return fmt.Errorf("report: failed to write meta dir: %w", err) + log.Printf("[Agent-Debug] Created temporary directory for coverage data: %s", tempDir) + // defer func() { + // if err := os.RemoveAll(tempDir); err != nil { + // log.Printf("[Agent] Error removing temp dir: %v", err) + // } + // }() + + err = coverage.WriteCountersDir(tempDir) + if err != nil { + return fmt.Errorf("failed to write coverage counters. Ensure the application was built with '-cover -covermode=atomic'. Original error: %w", err) } - log.Printf("[Agent] Report: WriteMetaDir OK") - - // Quick diagnostics: list what got written - listed := listDir(tempDir) - log.Printf("[Agent] Report: tempDir listing -> %d entries: %v", len(listed), listed) + log.Printf("[Agent-Debug] Successfully wrote coverage counters to %s", tempDir) - // Process with covdata and then ParseProfiles - executed, err := processCoverageProfilesUsingCovdata(tempDir) + err = coverage.WriteMetaDir(tempDir) if err != nil { - return fmt.Errorf("report: failed to process coverage profiles: %w", err) + return fmt.Errorf("failed to write meta dir: %w", err) } + log.Printf("[Agent-Debug] Successfully wrote meta data to %s", tempDir) - // Summarize results - totalFiles := 0 - totalLines := 0 - for f, lines := range executed { - totalFiles++ - totalLines += len(lines) - if len(lines) == 0 { - log.Printf("[Agent] Report: file=%s has 0 covered lines (unexpected since it’s present)", f) - } else { - // For very verbose mode, dump first few lines only to keep logs manageable - preview := lines - if len(lines) > 20 { - preview = lines[:20] - } - log.Printf("[Agent] Report: file=%s coveredLines=%d preview(first<=20)=%v", f, len(lines), preview) - } + log.Printf("[Agent-Debug] Processing coverage profiles from directory: %s", tempDir) + processedData, err := processCoverageProfilesUsingCovdata(tempDir) + if err != nil { + return fmt.Errorf("failed to process coverage profiles: %w", err) } + log.Printf("[Agent-Debug] Finished processing coverage profiles. Found coverage for %d files.", len(processedData)) - if totalLines == 0 { - log.Printf("[Agent-Warning] No covered lines were found for test %s. The report will be empty. (files=%d)", testID, totalFiles) + if len(processedData) == 0 { + log.Printf("[Agent-Warning] No covered lines were found for test %s. The report will be empty.", testID) } payload := map[string]interface{}{ "id": testID, - "executedLinesByFile": executed, + "executedLinesByFile": processedData, } jsonData, err := json.Marshal(payload) if err != nil { - return fmt.Errorf("report: failed to marshal coverage data to JSON: %w", err) + return fmt.Errorf("failed to marshal coverage data to JSON: %w", err) } - log.Printf("[Agent] Report: payload bytes=%d, files=%d, totalCoveredLines=%d", len(jsonData), totalFiles, totalLines) + log.Printf("[Agent-Debug] Marshalled JSON payload of size %d bytes for testID: '%s'", len(jsonData), testID) - // Send to data socket - if err := sendToSocket(jsonData); err != nil { - return fmt.Errorf("report: failed sending to data socket: %w", err) + log.Printf("[Agent-Debug] Sending coverage data to socket for testID: '%s'", testID) + err = sendToSocket(jsonData) + if err != nil { + log.Printf("[Agent-Debug] Error sending data to socket: %v", err) + return err } - log.Printf("[Agent] Report: sendToSocket OK in %s", time.Since(start)) + log.Printf("[Agent-Debug] Successfully sent coverage data to socket for testID: '%s'", testID) return nil } // sendToSocket connects to the Keploy data socket and writes the JSON payload. func sendToSocket(data []byte) error { - log.Printf("[Agent] DataSock: dialing %s", dataSocketPath) conn, err := net.Dial("unix", dataSocketPath) if err != nil { return fmt.Errorf("could not connect to keploy data socket at %s: %w", dataSocketPath, err) } defer func() { - log.Printf("[Agent] DataSock: closing connection") if err := conn.Close(); err != nil { - log.Printf("[Agent] DataSock: error closing connection: %v", err) + log.Printf("[Agent] Error closing connection: %v", err) } }() - n, err := conn.Write(data) - log.Printf("[Agent] DataSock: wrote %d bytes (err=%v)", n, err) + _, err = conn.Write(data) return err } // processCoverageProfilesUsingCovdata uses the covdata tool to convert binary coverage data to text format // and then processes it using the standard cover package. func processCoverageProfilesUsingCovdata(dir string) (map[string][]int, error) { - log.Printf("[Agent] Covdata: begin. dir=%s", dir) - - // Log go version for diagnostics - if out, err := exec.Command("go", "version").CombinedOutput(); err != nil { - log.Printf("[Agent] Covdata: 'go version' failed: %v (out=%q)", err, string(out)) - } else { - log.Printf("[Agent] Covdata: %s", strings.TrimSpace(string(out))) - } - + log.Printf("[Agent-Debug] processCoverageProfilesUsingCovdata called for directory: '%s'", dir) // Create a temporary file for the text format output textFile, err := os.CreateTemp("", "coverage-*.txt") if err != nil { - return nil, fmt.Errorf("covdata: failed to create temp file for text coverage: %w", err) + return nil, fmt.Errorf("failed to create temp file for text coverage: %w", err) } - log.Printf("[Agent] Covdata: text output file=%s", textFile.Name()) + log.Printf("[Agent-Debug] Created temporary text file: '%s'", textFile.Name()) + defer func() { + if err := os.Remove(textFile.Name()); err != nil { + log.Printf("[Agent] Error removing temp file: %v", err) + } + log.Printf("[Agent-Debug] Removed temporary text file: '%s'", textFile.Name()) + }() defer func() { - log.Printf("[Agent] Covdata: closing text file") if err := textFile.Close(); err != nil { - log.Printf("[Agent] Covdata: error closing temp file: %v", err) - } - log.Printf("[Agent] Covdata: removing text file %s", textFile.Name()) - if err := os.Remove(textFile.Name()); err != nil { - log.Printf("[Agent] Covdata: error removing temp file: %v", err) + log.Printf("[Agent] Error closing temp file: %v", err) } }() @@ -281,127 +246,102 @@ func processCoverageProfilesUsingCovdata(dir string) (map[string][]int, error) { cmd := exec.Command("go", "tool", "covdata", "textfmt", "-i="+dir, "-o="+textFile.Name()) var stderr bytes.Buffer cmd.Stderr = &stderr + log.Printf("[Agent-Debug] Executing command: %s", cmd.String()) - log.Printf("[Agent] Covdata: running %q", strings.Join(cmd.Args, " ")) - if err := cmd.Run(); err != nil { - return nil, fmt.Errorf("covdata: failed to convert coverage data to text format: %w; stderr: %s", err, stderr.String()) + err = cmd.Run() + if err != nil { + return nil, fmt.Errorf("failed to convert coverage data to text format: %w\nStderr: %s", err, stderr.String()) } - if s := strings.TrimSpace(stderr.String()); s != "" { - log.Printf("[Agent] Covdata: warnings/stderr: %s", s) + log.Printf("[Agent-Debug] Successfully executed 'go tool covdata'.") + + // Check the size of the output file + fileInfo, err := textFile.Stat() + if err != nil { + log.Printf("[Agent-Debug] Could not stat temporary text file '%s': %v", textFile.Name(), err) } else { - log.Printf("[Agent] Covdata: textfmt OK; stderr empty") + log.Printf("[Agent-Debug] Temporary text file '%s' has size: %d bytes.", textFile.Name(), fileInfo.Size()) + if fileInfo.Size() == 0 { + log.Printf("[Agent-Warning] The 'go tool covdata' command produced an empty output file. This likely means no coverage counters were set during the test run.") + } } // Get the module path (e.g., "your/module/path") to resolve file paths correctly. modulePathCmd := exec.Command("go", "list", "-m") var stderrModPath bytes.Buffer modulePathCmd.Stderr = &stderrModPath + log.Printf("[Agent-Debug] Executing command: %s", modulePathCmd.String()) modulePathBytes, err := modulePathCmd.Output() if err != nil { - return nil, fmt.Errorf("covdata: failed to get module path with 'go list -m': %w; stderr: %s", err, stderrModPath.String()) + return nil, fmt.Errorf("failed to get module path with 'go list -m': %w\nStderr: %s", err, stderrModPath.String()) } modulePath := strings.TrimSpace(string(modulePathBytes)) - log.Printf("[Agent] Covdata: modulePath=%q", modulePath) + log.Printf("[Agent-Debug] Detected module path: '%s'", modulePath) // Get the module's root directory on the filesystem. moduleDirCmd := exec.Command("go", "list", "-m", "-f", "{{.Dir}}") var stderrModDir bytes.Buffer moduleDirCmd.Stderr = &stderrModDir + log.Printf("[Agent-Debug] Executing command: %s", moduleDirCmd.String()) moduleDirBytes, err := moduleDirCmd.Output() if err != nil { - return nil, fmt.Errorf("covdata: failed to get module directory with 'go list -m -f {{.Dir}}': %w; stderr: %s", err, stderrModDir.String()) + return nil, fmt.Errorf("failed to get module directory with 'go list -m -f {{.Dir}}': %w\nStderr: %s", err, stderrModDir.String()) } moduleDir := strings.TrimSpace(string(moduleDirBytes)) - log.Printf("[Agent] Covdata: moduleDir=%q", moduleDir) + log.Printf("[Agent-Debug] Detected module directory: '%s'", moduleDir) // Parse the text format using the standard cover package. - log.Printf("[Agent] Covdata: parsing profiles from %s", textFile.Name()) + log.Printf("[Agent-Debug] Parsing text coverage profile from: '%s'", textFile.Name()) profiles, err := cover.ParseProfiles(textFile.Name()) if err != nil { - return nil, fmt.Errorf("covdata: failed to parse text coverage profile: %w", err) + return nil, fmt.Errorf("failed to parse text coverage profile: %w", err) } - log.Printf("[Agent] Covdata: parsed %d profiles", len(profiles)) + log.Printf("[Agent-Debug] Parsed %d profiles from the coverage file.", len(profiles)) executedLinesByFile := make(map[string][]int) for i, profile := range profiles { - log.Printf("[Agent] Covdata: profile[%d] fileName=%q blocks=%d", i, profile.FileName, len(profile.Blocks)) - + log.Printf("[Agent-Debug] Processing profile #%d for file: '%s'", i+1, profile.FileName) var absolutePath string - switch { - case strings.HasPrefix(profile.FileName, modulePath): + if strings.HasPrefix(profile.FileName, modulePath) { relativePath := strings.TrimPrefix(profile.FileName, modulePath) absolutePath = filepath.Join(moduleDir, relativePath) - log.Printf("[Agent] Covdata: resolved via modulePath => %s", absolutePath) - case !filepath.IsAbs(profile.FileName): - log.Printf("[Agent] Covdata: skipping non-absolute non-module path file=%q", profile.FileName) + log.Printf("[Agent-Debug] Profile #%d: Matched module path. Relative path: '%s', Absolute path: '%s'", i+1, relativePath, absolutePath) + } else if !filepath.IsAbs(profile.FileName) { + log.Printf("[Agent-Debug] Profile #%d: Skipping file '%s' because it is not an absolute path and does not match the module path.", i+1, profile.FileName) continue - default: + } else { absolutePath = profile.FileName - log.Printf("[Agent] Covdata: absolute path taken => %s", absolutePath) + log.Printf("[Agent-Debug] Profile #%d: Using existing absolute path: '%s'", i+1, absolutePath) } lineSet := make(map[int]bool) - totalPositive := 0 + log.Printf("[Agent-Debug] Profile #%d has %d blocks to process.", i+1, len(profile.Blocks)) // For each block in the profile, if the count is greater than 0, add the lines to the map. for j, block := range profile.Blocks { if block.Count <= 0 { - // This block wasn't executed continue } - totalPositive++ + log.Printf("[Agent-Debug] Profile #%d, Block #%d: Count is %d. Processing lines %d to %d.", i+1, j+1, block.Count, block.StartLine, block.EndLine) for line := block.StartLine; line <= block.EndLine; line++ { lineSet[line] = true } - if j < 5 { // limit per-profile spam - log.Printf("[Agent] Covdata: block[%d] start=%d end=%d count=%d", j, block.StartLine, block.EndLine, block.Count) - } - } - - if len(lineSet) == 0 { - log.Printf("[Agent] Covdata: file=%s has 0 executed lines; positiveBlocks=%d (might indicate counters not flushed or build flags missing)", absolutePath, totalPositive) - continue } - lines := make([]int, 0, len(lineSet)) - for line := range lineSet { - lines = append(lines, line) + // If there are any lines executed, add them to the map. + if len(lineSet) > 0 { + lines := make([]int, 0, len(lineSet)) + for line := range lineSet { + lines = append(lines, line) + } + sort.Ints(lines) + executedLinesByFile[absolutePath] = lines + log.Printf("[Agent-Debug] Profile #%d: Found %d executed lines for file '%s'.", i+1, len(lines), absolutePath) + } else { + log.Printf("[Agent-Debug] Profile #%d: No executed lines found for file '%s' after processing all blocks.", i+1, absolutePath) } - sort.Ints(lines) - executedLinesByFile[absolutePath] = lines - log.Printf("[Agent] Covdata: file=%s executedLines=%d", absolutePath, len(lines)) } - log.Printf("[Agent] Covdata: executed files=%d", len(executedLinesByFile)) + log.Printf("[Agent-Debug] Final processed data contains coverage for %d files.", len(executedLinesByFile)) return executedLinesByFile, nil } - -// helpers - -func listDir(dir string) []string { - entries, err := os.ReadDir(dir) - if err != nil { - return []string{fmt.Sprintf("ERR: %v", err)} - } - var out []string - for _, e := range entries { - name := e.Name() - full := filepath.Join(dir, name) - info, err := e.Info() - if err != nil { - out = append(out, fmt.Sprintf("%s (err: %v)", name, err)) - continue - } - out = append(out, fmt.Sprintf("%s size=%d mode=%s", full, info.Size(), info.Mode())) - } - return out -} - -func mustGetwd() string { - wd, err := os.Getwd() - if err != nil { - return fmt.Sprintf("ERR:%v", err) - } - return wd -} From 892cfe35fab77648a3acbddc8eb742795125d6c9 Mon Sep 17 00:00:00 2001 From: Asish Kumar Date: Wed, 17 Sep 2025 08:19:09 +0000 Subject: [PATCH 4/6] feat: add more logs Signed-off-by: Asish Kumar --- keploy/keploy.go | 128 +++++++++++++++++++++++++++++++---------------- 1 file changed, 84 insertions(+), 44 deletions(-) diff --git a/keploy/keploy.go b/keploy/keploy.go index 57986c2..82a0a3e 100644 --- a/keploy/keploy.go +++ b/keploy/keploy.go @@ -17,6 +17,7 @@ import ( "os" "os/exec" "path/filepath" + "runtime" "runtime/coverage" "sort" "strings" @@ -41,6 +42,7 @@ var ( // init starts the background control server that listens for commands from the Keploy test runner. func init() { + log.Printf("[Agent-Init] Starting control server. GOOS=%s GOARCH=%s PID=%d", runtime.GOOS, runtime.GOARCH, os.Getpid()) go startControlServer() } @@ -51,12 +53,15 @@ func startControlServer() { log.Printf("[Agent] Failed to remove old control socket: %v", err) return } + log.Printf("[Agent-Init] Control socket cleared. Path=%s", controlSocketPath) ln, err := net.Listen("unix", controlSocketPath) if err != nil { log.Printf("[Agent] 🚨 FATAL: Could not start control server: %v", err) return } + log.Printf("[Agent] Control server listening on %s (cwd=%s)", controlSocketPath, mustGetwd()) + defer func() { if err := ln.Close(); err != nil { log.Printf("[Agent] Error closing control server: %v", err) @@ -67,11 +72,13 @@ func startControlServer() { conn, err := ln.Accept() if err != nil { if strings.Contains(err.Error(), "use of closed network connection") { + log.Printf("[Agent] Listener closed, exiting control loop") break } log.Printf("[Agent] Error accepting connection: %v", err) continue } + log.Printf("[Agent-Debug] New controller connection from local process") go handleControlRequest(conn) } } @@ -93,40 +100,40 @@ func handleControlRequest(conn net.Conn) { // Split the command into action and testID parts := strings.SplitN(strings.TrimSpace(command), " ", 2) + log.Printf("[Agent-Debug] Command parts len=%d; parts=%q", len(parts), parts) if len(parts) != 2 { - log.Printf("[Agent-Debug] Invalid command format: '%s'", command) + log.Printf("[Agent-Debug] Invalid command format: '%s' (expected: ' ')", command) return } action, id := parts[0], parts[1] - log.Printf("[Agent-Debug] Parsed command. Action: '%s', ID: '%s'", action, id) + log.Printf("[Agent-Debug] Parsed command. Action='%s', ID='%s'", action, id) controlMu.Lock() defer controlMu.Unlock() switch action { case "START": - log.Printf("[Agent-Debug] Handling START command for test ID: '%s'", id) + log.Printf("[Agent-Debug] Handling START for test ID='%s' (prev currentTestID='%s')", id, currentTestID) currentTestID = id err := coverage.ClearCounters() if err != nil { log.Printf("[Agent-Debug] Error clearing coverage counters: %v", err) } else { - log.Printf("[Agent-Debug] Successfully cleared coverage counters for test ID: '%s'", id) + log.Printf("[Agent-Debug] Cleared coverage counters for test ID='%s'", id) } case "END": - log.Printf("[Agent-Debug] Handling END command for test ID: '%s'", id) + log.Printf("[Agent-Debug] Handling END for test ID='%s' (currentTestID='%s')", id, currentTestID) if currentTestID != id { - log.Printf("[Agent-Debug] Warning: Mismatched END command. Expected '%s', got '%s'. Skipping coverage report to avoid inconsistent state.", currentTestID, id) + log.Printf("[Agent-Debug] Warning: Mismatched END. Expected '%s', got '%s'. Skipping coverage report.", currentTestID, id) return } err := reportCoverage(id) if err != nil { log.Printf("[Agent] 🚨 Error reporting coverage for test %s: %v", id, err) } else { - log.Printf("[Agent-Debug] Successfully initiated coverage report for test ID: '%s'", id) + log.Printf("[Agent-Debug] Coverage report initiated for test ID='%s'", id) } - // Reset the currentTestID to an empty string to indicate that no test is currently being recorded. - log.Printf("[Agent-Debug] Resetting currentTestID from '%s' to empty.", currentTestID) + log.Printf("[Agent-Debug] Resetting currentTestID from '%s' to ''", currentTestID) currentTestID = "" _, err = conn.Write([]byte("ACK\n")) @@ -140,19 +147,21 @@ func handleControlRequest(conn net.Conn) { // reportCoverage dumps, processes, and sends the coverage data. func reportCoverage(testID string) error { - log.Printf("[Agent-Debug] Starting reportCoverage for testID: '%s'", testID) + log.Printf("[Agent-Debug] reportCoverage start. testID='%s'", testID) + // Only take the part before the first slash, // e.g. "test-2" from "test-set-0/test-2" parts := strings.SplitN(testID, "/", 2) - baseID := parts[1] - log.Printf("[Agent-Debug] Extracted baseID: '%s'", baseID) + log.Printf("[Agent-Debug] testID split parts len=%d; parts=%q", len(parts), parts) + baseID := parts[1] // NOTE: current behavior; will panic if len(parts)<2 + log.Printf("[Agent-Debug] baseID derived='%s' (NOTE: uses parts[1])", baseID) // Create a temporary directory to store the coverage data. tempDir, err := os.MkdirTemp("", fmt.Sprintf("keploy-coverage-%s-", baseID)) if err != nil { return fmt.Errorf("failed to create temp dir: %w", err) } - log.Printf("[Agent-Debug] Created temporary directory for coverage data: %s", tempDir) + log.Printf("[Agent-Debug] Temp coverage dir: %s", tempDir) // defer func() { // if err := os.RemoveAll(tempDir); err != nil { // log.Printf("[Agent] Error removing temp dir: %v", err) @@ -163,23 +172,23 @@ func reportCoverage(testID string) error { if err != nil { return fmt.Errorf("failed to write coverage counters. Ensure the application was built with '-cover -covermode=atomic'. Original error: %w", err) } - log.Printf("[Agent-Debug] Successfully wrote coverage counters to %s", tempDir) + log.Printf("[Agent-Debug] Wrote coverage counters -> %s", tempDir) err = coverage.WriteMetaDir(tempDir) if err != nil { return fmt.Errorf("failed to write meta dir: %w", err) } - log.Printf("[Agent-Debug] Successfully wrote meta data to %s", tempDir) + log.Printf("[Agent-Debug] Wrote meta data -> %s", tempDir) - log.Printf("[Agent-Debug] Processing coverage profiles from directory: %s", tempDir) + log.Printf("[Agent-Debug] Processing coverage profiles from dir: %s", tempDir) processedData, err := processCoverageProfilesUsingCovdata(tempDir) if err != nil { return fmt.Errorf("failed to process coverage profiles: %w", err) } - log.Printf("[Agent-Debug] Finished processing coverage profiles. Found coverage for %d files.", len(processedData)) + log.Printf("[Agent-Debug] Finished processing profiles. Files with coverage=%d", len(processedData)) if len(processedData) == 0 { - log.Printf("[Agent-Warning] No covered lines were found for test %s. The report will be empty.", testID) + log.Printf("[Agent-Warning] No covered lines found for test %s. The report will be empty.", testID) } payload := map[string]interface{}{ @@ -191,15 +200,15 @@ func reportCoverage(testID string) error { if err != nil { return fmt.Errorf("failed to marshal coverage data to JSON: %w", err) } - log.Printf("[Agent-Debug] Marshalled JSON payload of size %d bytes for testID: '%s'", len(jsonData), testID) + log.Printf("[Agent-Debug] JSON payload size=%d bytes for testID='%s'", len(jsonData), testID) - log.Printf("[Agent-Debug] Sending coverage data to socket for testID: '%s'", testID) + log.Printf("[Agent-Debug] Sending coverage JSON to data socket: %s", dataSocketPath) err = sendToSocket(jsonData) if err != nil { log.Printf("[Agent-Debug] Error sending data to socket: %v", err) return err } - log.Printf("[Agent-Debug] Successfully sent coverage data to socket for testID: '%s'", testID) + log.Printf("[Agent-Debug] Successfully sent coverage JSON for testID='%s'", testID) return nil } @@ -209,20 +218,25 @@ func sendToSocket(data []byte) error { if err != nil { return fmt.Errorf("could not connect to keploy data socket at %s: %w", dataSocketPath, err) } + log.Printf("[Agent-Debug] Connected to data socket: %s", dataSocketPath) defer func() { if err := conn.Close(); err != nil { - log.Printf("[Agent] Error closing connection: %v", err) + log.Printf("[Agent] Error closing data socket connection: %v", err) } }() - _, err = conn.Write(data) + n, err := conn.Write(data) + log.Printf("[Agent-Debug] Wrote %d bytes to data socket (err=%v)", n, err) return err } // processCoverageProfilesUsingCovdata uses the covdata tool to convert binary coverage data to text format // and then processes it using the standard cover package. func processCoverageProfilesUsingCovdata(dir string) (map[string][]int, error) { - log.Printf("[Agent-Debug] processCoverageProfilesUsingCovdata called for directory: '%s'", dir) + log.Printf("[Agent-Debug] processCoverageProfilesUsingCovdata(dir=%s) cwd=%s", dir, mustGetwd()) + log.Printf("[Agent-Debug] Env: GOMOD=%q GOPATH=%q GOROOT=%q PATH(head)=%q", + os.Getenv("GOMOD"), os.Getenv("GOPATH"), os.Getenv("GOROOT"), headPath(os.Getenv("PATH"))) + // Create a temporary file for the text format output textFile, err := os.CreateTemp("", "coverage-*.txt") if err != nil { @@ -246,22 +260,22 @@ func processCoverageProfilesUsingCovdata(dir string) (map[string][]int, error) { cmd := exec.Command("go", "tool", "covdata", "textfmt", "-i="+dir, "-o="+textFile.Name()) var stderr bytes.Buffer cmd.Stderr = &stderr - log.Printf("[Agent-Debug] Executing command: %s", cmd.String()) + log.Printf("[Agent-Debug] Executing: %s (cwd=%s)", cmd.String(), mustGetwd()) err = cmd.Run() if err != nil { return nil, fmt.Errorf("failed to convert coverage data to text format: %w\nStderr: %s", err, stderr.String()) } - log.Printf("[Agent-Debug] Successfully executed 'go tool covdata'.") + log.Printf("[Agent-Debug] 'go tool covdata' ok. stderr=%q", stderr.String()) // Check the size of the output file fileInfo, err := textFile.Stat() if err != nil { - log.Printf("[Agent-Debug] Could not stat temporary text file '%s': %v", textFile.Name(), err) + log.Printf("[Agent-Debug] Stat failed for '%s': %v", textFile.Name(), err) } else { - log.Printf("[Agent-Debug] Temporary text file '%s' has size: %d bytes.", textFile.Name(), fileInfo.Size()) + log.Printf("[Agent-Debug] Text coverage file size=%d bytes", fileInfo.Size()) if fileInfo.Size() == 0 { - log.Printf("[Agent-Warning] The 'go tool covdata' command produced an empty output file. This likely means no coverage counters were set during the test run.") + log.Printf("[Agent-Warning] 'go tool covdata' produced empty output; likely no counters set.") } } @@ -269,25 +283,30 @@ func processCoverageProfilesUsingCovdata(dir string) (map[string][]int, error) { modulePathCmd := exec.Command("go", "list", "-m") var stderrModPath bytes.Buffer modulePathCmd.Stderr = &stderrModPath - log.Printf("[Agent-Debug] Executing command: %s", modulePathCmd.String()) + log.Printf("[Agent-Debug] Executing: %s (cwd=%s)", modulePathCmd.String(), mustGetwd()) modulePathBytes, err := modulePathCmd.Output() if err != nil { + log.Printf("[Agent-Error] 'go list -m' failed. stderr=%s", stderrModPath.String()) return nil, fmt.Errorf("failed to get module path with 'go list -m': %w\nStderr: %s", err, stderrModPath.String()) } modulePath := strings.TrimSpace(string(modulePathBytes)) - log.Printf("[Agent-Debug] Detected module path: '%s'", modulePath) + log.Printf("[Agent-Debug] Detected module path: %q (len=%d)", modulePath, len(modulePath)) // Get the module's root directory on the filesystem. moduleDirCmd := exec.Command("go", "list", "-m", "-f", "{{.Dir}}") var stderrModDir bytes.Buffer moduleDirCmd.Stderr = &stderrModDir - log.Printf("[Agent-Debug] Executing command: %s", moduleDirCmd.String()) + log.Printf("[Agent-Debug] Executing: %s (cwd=%s)", moduleDirCmd.String(), mustGetwd()) moduleDirBytes, err := moduleDirCmd.Output() if err != nil { + log.Printf("[Agent-Error] 'go list -m -f {{.Dir}}' failed. stderr=%s", stderrModDir.String()) return nil, fmt.Errorf("failed to get module directory with 'go list -m -f {{.Dir}}': %w\nStderr: %s", err, stderrModDir.String()) } moduleDir := strings.TrimSpace(string(moduleDirBytes)) - log.Printf("[Agent-Debug] Detected module directory: '%s'", moduleDir) + if moduleDir == "" { + log.Printf("[Agent-Warning] Module directory is empty. Did you copy go.mod into the runtime image and set GOMOD?") + } + log.Printf("[Agent-Debug] Detected module directory: %q", moduleDir) // Parse the text format using the standard cover package. log.Printf("[Agent-Debug] Parsing text coverage profile from: '%s'", textFile.Name()) @@ -298,37 +317,38 @@ func processCoverageProfilesUsingCovdata(dir string) (map[string][]int, error) { log.Printf("[Agent-Debug] Parsed %d profiles from the coverage file.", len(profiles)) executedLinesByFile := make(map[string][]int) + skipped := 0 for i, profile := range profiles { - log.Printf("[Agent-Debug] Processing profile #%d for file: '%s'", i+1, profile.FileName) + log.Printf("[Agent-Debug] Processing profile #%d file='%s'", i+1, profile.FileName) var absolutePath string if strings.HasPrefix(profile.FileName, modulePath) { relativePath := strings.TrimPrefix(profile.FileName, modulePath) absolutePath = filepath.Join(moduleDir, relativePath) - log.Printf("[Agent-Debug] Profile #%d: Matched module path. Relative path: '%s', Absolute path: '%s'", i+1, relativePath, absolutePath) + log.Printf("[Agent-Debug] Profile #%d matched modulePath. rel='%s' abs='%s'", i+1, relativePath, absolutePath) } else if !filepath.IsAbs(profile.FileName) { - log.Printf("[Agent-Debug] Profile #%d: Skipping file '%s' because it is not an absolute path and does not match the module path.", i+1, profile.FileName) + skipped++ + log.Printf("[Agent-Warning] Profile #%d SKIP file='%s' reason='not absolute & no module prefix match' modulePath=%q moduleDir=%q", + i+1, profile.FileName, modulePath, moduleDir) continue } else { absolutePath = profile.FileName - log.Printf("[Agent-Debug] Profile #%d: Using existing absolute path: '%s'", i+1, absolutePath) + log.Printf("[Agent-Debug] Profile #%d using absolute path: '%s'", i+1, absolutePath) } lineSet := make(map[int]bool) - log.Printf("[Agent-Debug] Profile #%d has %d blocks to process.", i+1, len(profile.Blocks)) - // For each block in the profile, if the count is greater than 0, add the lines to the map. + log.Printf("[Agent-Debug] Profile #%d blocks=%d", i+1, len(profile.Blocks)) for j, block := range profile.Blocks { if block.Count <= 0 { continue } - log.Printf("[Agent-Debug] Profile #%d, Block #%d: Count is %d. Processing lines %d to %d.", i+1, j+1, block.Count, block.StartLine, block.EndLine) + log.Printf("[Agent-Trace] Profile #%d Block #%d count=%d lines=%d..%d", i+1, j+1, block.Count, block.StartLine, block.EndLine) for line := block.StartLine; line <= block.EndLine; line++ { lineSet[line] = true } } - // If there are any lines executed, add them to the map. if len(lineSet) > 0 { lines := make([]int, 0, len(lineSet)) for line := range lineSet { @@ -336,12 +356,32 @@ func processCoverageProfilesUsingCovdata(dir string) (map[string][]int, error) { } sort.Ints(lines) executedLinesByFile[absolutePath] = lines - log.Printf("[Agent-Debug] Profile #%d: Found %d executed lines for file '%s'.", i+1, len(lines), absolutePath) + log.Printf("[Agent-Debug] Profile #%d: collected %d executed lines for '%s'", i+1, len(lines), absolutePath) } else { - log.Printf("[Agent-Debug] Profile #%d: No executed lines found for file '%s' after processing all blocks.", i+1, absolutePath) + log.Printf("[Agent-Debug] Profile #%d: 0 executed lines after processing blocks for '%s'", i+1, absolutePath) } } - log.Printf("[Agent-Debug] Final processed data contains coverage for %d files.", len(executedLinesByFile)) + log.Printf("[Agent-Debug] Final processed data: filesWithCoverage=%d, profilesParsed=%d, profilesSkipped=%d", + len(executedLinesByFile), len(profiles), skipped) return executedLinesByFile, nil } + +func mustGetwd() string { + wd, err := os.Getwd() + if err != nil { + return "" + } + return wd +} + +func headPath(p string) string { + // show first entry of PATH to avoid overly long logs + if p == "" { + return "" + } + if i := strings.IndexByte(p, ':'); i >= 0 { + return p[:i] + } + return p +} From bee9f94f33ce28fffcf712f657affe1467746e21 Mon Sep 17 00:00:00 2001 From: kapish Date: Wed, 26 Nov 2025 14:39:14 +0000 Subject: [PATCH 5/6] feat: startup hooks for dedup Signed-off-by: kapish --- keploy/keploy.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/keploy/keploy.go b/keploy/keploy.go index 82a0a3e..415d4ea 100644 --- a/keploy/keploy.go +++ b/keploy/keploy.go @@ -30,7 +30,7 @@ const ( // controlSocketPath is used by Keploy to send commands (START/END) to the app. controlSocketPath = "/tmp/coverage_control.sock" // dataSocketPath is used by the app to send coverage data back to Keploy. - dataSocketPath = "/tmp/coverage_data.sock" + dataSocketPath = "@keploy_data_sock" ) var ( @@ -54,7 +54,6 @@ func startControlServer() { return } log.Printf("[Agent-Init] Control socket cleared. Path=%s", controlSocketPath) - ln, err := net.Listen("unix", controlSocketPath) if err != nil { log.Printf("[Agent] 🚨 FATAL: Could not start control server: %v", err) From a32373bc39fbbb87f15da446ba7335cc310584ed Mon Sep 17 00:00:00 2001 From: kapish Date: Thu, 27 Nov 2025 06:31:49 +0000 Subject: [PATCH 6/6] feat: startup hooks for dedup Signed-off-by: kapish --- keploy/keploy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keploy/keploy.go b/keploy/keploy.go index 415d4ea..57c939f 100644 --- a/keploy/keploy.go +++ b/keploy/keploy.go @@ -30,7 +30,7 @@ const ( // controlSocketPath is used by Keploy to send commands (START/END) to the app. controlSocketPath = "/tmp/coverage_control.sock" // dataSocketPath is used by the app to send coverage data back to Keploy. - dataSocketPath = "@keploy_data_sock" + dataSocketPath = "/tmp/coverage_data.sock" ) var (