MCPcopy Create free account
hub / github.com/Scalingo/cli / Dump

Function Dump

logs/logs.go:39–112  ·  view source on GitHub ↗
(ctx context.Context, logsURL string, n int, filter string)

Source from the content-addressed store, hash-verified

37}
38
39func Dump(ctx context.Context, logsURL string, n int, filter string) error {
40 c, err := config.ScalingoClient(ctx)
41 if err != nil {
42 return errors.Wrapf(ctx, err, "fail to get Scalingo client")
43 }
44
45 readCloser, err := c.Logs(ctx, logsURL, n, filter)
46 if errors.Is(err, scalingo.ErrNoLogs) {
47 io.Error("There is no log for this application")
48 io.Info("Ensure your application is writing to the standard output")
49 return nil
50 } else if err != nil {
51 return errors.Wrap(ctx, err, "fetch logs")
52 }
53 defer readCloser.Close()
54
55 // Create a buffered channel with a maximum size of the number of log lines
56 // requested. On medium to good internet connection, we are fetching lines
57 // faster than we can process them. This buffer is here to get the logs as
58 // fast as possible since the request will time out after 30s.
59 //
60 // Cap the size of the buffer (to prevent high memory allocation when user specify n=1_000_000)
61 buffSize := min(n, logsMaxBufferSize)
62
63 // This buffered channel will be used as a buffer between the network
64 // connection and our logs processing pipeline.
65 buff := make(chan string, buffSize)
66 // This waitgroup is used to ensure that the logs processing pipeline is
67 // finished before exiting the method.
68 wg := &sync.WaitGroup{}
69
70 // Start a goroutine that will read from buffered channel and send those
71 // lines to the logs processing pipeline.
72 wg.Go(func() {
73 for bline := range buff {
74 colorizeLogs(bline)
75 }
76 })
77
78 // Ensure that all lines are printed out before exiting this method.
79 defer wg.Wait()
80
81 // Here we used bufio to read from the response because we want to easily
82 // split response in lines.
83 // Note: This can look like a duplicate measure with our buffered channel
84 // (buff) however it's not. The reason is that ReadBytes will fill the sr
85 // Reader only if the internal buffer is empty. This means that the first
86 // ReadBytes will fetch 4MB of data from the connection. Then it will use
87 // this internal buffer until it runs out. However if our logs processing
88 // pipeline is slow, it will never query the next 4MB of data. Hence the
89 // buffered channel.
90 sr := bufio.NewReader(readCloser)
91
92 for {
93 // Read one line from the response
94 bline, err := sr.ReadBytes('\n')
95
96 if err != nil {

Callers 2

LogsFunction · 0.92
LogsFunction · 0.92

Calls 4

ScalingoClientFunction · 0.92
ErrorFunction · 0.92
InfoFunction · 0.92
colorizeLogsFunction · 0.85

Tested by

no test coverage detected