6
6
"encoding/json"
7
7
"fmt"
8
8
"net/http"
9
+ "runtime"
9
10
"strconv"
10
11
"strings"
11
12
@@ -721,7 +722,7 @@ func getJobLogData(ctx context.Context, client *github.Client, owner, repo strin
721
722
722
723
if returnContent {
723
724
// Download and return the actual log content
724
- content , originalLength , httpResp , err := downloadLogContent (url .String (), tailLines ) //nolint:bodyclose // Response body is closed in downloadLogContent, but we need to return httpResp
725
+ content , originalLength , httpResp , err := downloadLogContent (ctx , url .String (), tailLines ) //nolint:bodyclose // Response body is closed in downloadLogContent, but we need to return httpResp
725
726
if err != nil {
726
727
// To keep the return value consistent wrap the response as a GitHub Response
727
728
ghRes := & github.Response {
@@ -742,8 +743,7 @@ func getJobLogData(ctx context.Context, client *github.Client, owner, repo strin
742
743
return result , resp , nil
743
744
}
744
745
745
- // downloadLogContent downloads the actual log content from a GitHub logs URL
746
- func downloadLogContent (logURL string , tailLines int ) (string , int , * http.Response , error ) {
746
+ func downloadLogContent (ctx context.Context , logURL string , tailLines int ) (string , int , * http.Response , error ) {
747
747
httpResp , err := http .Get (logURL ) //nolint:gosec
748
748
if err != nil {
749
749
return "" , 0 , httpResp , fmt .Errorf ("failed to download logs: %w" , err )
@@ -758,40 +758,56 @@ func downloadLogContent(logURL string, tailLines int) (string, int, *http.Respon
758
758
tailLines = 1000
759
759
}
760
760
761
- const maxMemoryBytes = 5 * 1024 * 1024
762
- var lines []string
761
+ const maxLines = 50000
762
+
763
+ lines := make ([]string , maxLines )
763
764
totalLines := 0
764
- currentMemoryUsage := 0
765
+ writeIndex := 0
765
766
766
767
scanner := bufio .NewScanner (httpResp .Body )
767
768
scanner .Buffer (make ([]byte , 0 , 64 * 1024 ), 1024 * 1024 )
768
769
769
770
for scanner .Scan () {
770
771
line := scanner .Text ()
771
772
totalLines ++
772
- lineSize := len (line ) + 1
773
773
774
- // Remove lines from the front until we have space for the new line
775
- for currentMemoryUsage + lineSize > maxMemoryBytes && len (lines ) > 0 {
776
- removedLineSize := len (lines [0 ]) + 1
777
- currentMemoryUsage -= removedLineSize
778
- lines = lines [1 :]
779
- }
774
+ lines [writeIndex ] = line
775
+ writeIndex = (writeIndex + 1 ) % maxLines
780
776
781
- // Add the new line
782
- lines = append ( lines , line )
783
- currentMemoryUsage += lineSize
777
+ if totalLines % 10000 == 0 {
778
+ runtime . GC ( )
779
+ }
784
780
}
785
781
786
782
if err := scanner .Err (); err != nil {
787
783
return "" , 0 , httpResp , fmt .Errorf ("failed to read log content: %w" , err )
788
784
}
789
785
790
- if len (lines ) > tailLines {
791
- lines = lines [len (lines )- tailLines :]
786
+ var result []string
787
+ linesInBuffer := totalLines
788
+ if linesInBuffer > maxLines {
789
+ linesInBuffer = maxLines
792
790
}
793
791
794
- return strings .Join (lines , "\n " ), totalLines , httpResp , nil
792
+ startIndex := 0
793
+ if totalLines > maxLines {
794
+ startIndex = writeIndex
795
+ }
796
+
797
+ for i := 0 ; i < linesInBuffer ; i ++ {
798
+ idx := (startIndex + i ) % maxLines
799
+ if lines [idx ] != "" {
800
+ result = append (result , lines [idx ])
801
+ }
802
+ }
803
+
804
+ if len (result ) > tailLines {
805
+ result = result [len (result )- tailLines :]
806
+ }
807
+
808
+ finalResult := strings .Join (result , "\n " )
809
+
810
+ return finalResult , totalLines , httpResp , nil
795
811
}
796
812
797
813
// RerunWorkflowRun creates a tool to re-run an entire workflow run
0 commit comments