@@ -98,16 +98,67 @@ private static function logs( $lines = 500 ) {
9898 while ( ftell ( $ socket ) > 0 && $ lines >= 0 ) {
9999 $ seek = min ( ftell ( $ socket ), $ buffer );
100100
101+ // Move pointer backward, then read and return to the initial position.
101102 fseek ( $ socket , -$ seek , SEEK_CUR );
103+ $ chunk = fread ( $ socket , $ seek );
104+ fseek ( $ socket , -mb_strlen ( $ chunk , '8bit ' ), SEEK_CUR );
102105
103- $ chunk = fread ( $ socket , $ seek );
106+ // Prepend chunk to the output as we're reading logs right to left.
104107 $ output = $ chunk . $ output ;
105108
106- fseek ( $ socket , -mb_strlen ( $ chunk , '8bit ' ), SEEK_CUR );
109+ $ cursor = ftell ( $ socket );
110+ $ line_breaks = substr_count ( $ chunk , "\n" );
111+
112+ // Ellipsis lines if no line breaks in a buffer span to save memory.
113+ if ( ! $ line_breaks && ftell ( $ socket ) > 0 ) {
114+ // First, move the cursor to the last line break and remove the offset from the output.
115+ $ offset = strpos ( $ output , "\n" );
116+ if ( false !== $ offset ) {
117+ $ output = substr ( $ output , $ offset );
118+ fseek ( $ socket , $ offset , SEEK_CUR );
119+ $ cursor = ftell ( $ socket );
120+ }
121+
122+ // Then loops until some line break is found, or the end of the file is reached.
123+ while ( ! $ line_breaks && ftell ( $ socket ) > 0 ) {
124+ $ seek = min ( ftell ( $ socket ), $ buffer );
125+
126+ fseek ( $ socket , -$ seek , SEEK_CUR );
127+ $ chunk = fread ( $ socket , $ seek );
128+ fseek ( $ socket , -mb_strlen ( $ chunk , '8bit ' ), SEEK_CUR );
129+
130+ $ line_breaks = substr_count ( $ chunk , "\n" );
131+ }
132+
133+ // Move the cursor to the first line break match.
134+ if ( $ line_breaks ) {
135+ $ offset = strrpos ( $ chunk , "\n" ) + 1 ;
136+ fseek ( $ socket , $ offset , SEEK_CUR );
137+ }
138+
139+ // Read a new chunk starting at the new cursor.
140+ $ new_cursor = ftell ( $ socket );
141+ $ seek = min ( $ buffer , $ cursor - $ new_cursor );
142+ $ chunk = fread ( $ socket , $ seek );
143+ fseek ( $ socket , -mb_strlen ( $ chunk , '8bit ' ), SEEK_CUR );
144+
145+ // If chunk ends at cursor, there is no gap between the current output
146+ // and the last chunk. Skip ellipsis.
147+ if ( $ new_cursor + $ seek === $ cursor ) {
148+ $ output = $ chunk . $ output ;
149+ } else {
150+ $ output = $ chunk . '... ' . $ output ;
151+ }
152+
153+ // Cursor is at the fist line break, or at the beginning of the file.
154+ // In any cases, we didn't substract any line to the line counter.
155+ $ line_breaks = 0 ;
156+ }
107157
108- $ lines -= substr_count ( $ chunk , "\n" ) ;
158+ $ lines -= $ line_breaks ;
109159 }
110160
161+ // In case the loop reads more lines than required, shift lines from the output.
111162 while ( $ lines ++ < 0 ) {
112163 $ output = substr ( $ output , strpos ( $ output , "\n" ) + 1 );
113164 }
0 commit comments