Skip to content

Commit 1662901

Browse files
Add 'last' flag to print the last n lines of the log and implement ReadLastLines utility
1 parent bf7834b commit 1662901

3 files changed

Lines changed: 98 additions & 5 deletions

File tree

cmd/printlog.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,9 @@ func init() {
5555
if err := viper.BindPFlag("totals", printlogCmd.Flags().Lookup("totals")); err != nil {
5656
log.Printf("Error binding flag 'totals': %v", err)
5757
}
58+
59+
printlogCmd.Flags().Int16P("last", "l", 0, "Prints only the last n lines of the log file.")
60+
if err := viper.BindPFlag("last", printlogCmd.Flags().Lookup("last")); err != nil {
61+
log.Printf("Error binding flag 'last': %v", err)
62+
}
5863
}

utils/lastlines.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
Copyright © 2025 Tim Kennedy
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.
21+
*/
22+
23+
package utils
24+
25+
import (
26+
"io"
27+
"os"
28+
)
29+
30+
func ReadLastLines(filePath string, numLines int) ([]string, error) {
31+
file, err := os.Open(filePath)
32+
if err != nil {
33+
return nil, err
34+
}
35+
defer file.Close()
36+
37+
stat, err := file.Stat()
38+
if err != nil {
39+
return nil, err
40+
}
41+
42+
var lines []string
43+
offset := stat.Size()
44+
buffer := make([]byte, 1)
45+
line := ""
46+
47+
for offset > 0 && len(lines) < numLines {
48+
offset--
49+
_, err := file.Seek(offset, io.SeekStart)
50+
if err != nil {
51+
return nil, err
52+
}
53+
54+
_, err = file.Read(buffer)
55+
if err != nil {
56+
return nil, err
57+
}
58+
59+
if buffer[0] == '\n' {
60+
if line != "" {
61+
lines = append([]string{line}, lines...)
62+
line = ""
63+
}
64+
} else {
65+
line = string(buffer[0]) + line
66+
}
67+
}
68+
69+
if line != "" && len(lines) < numLines {
70+
lines = append([]string{line}, lines...)
71+
}
72+
73+
return lines, nil
74+
}

utils/printlog.go

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,31 @@ func PrintLog() error {
6060
}
6161
defer file.Close()
6262

63-
// Using bufio scanner here for memory-efficient line-by-line reading.
6463
lineCounter := 0
6564
scanner := bufio.NewScanner(file)
66-
for scanner.Scan() {
67-
fmt.Println(scanner.Text())
68-
lineCounter++
65+
getLast := viper.GetInt("last")
66+
67+
if getLast > 0 {
68+
lastLines, _ := ReadLastLines(logFile, getLast)
69+
for _, line := range lastLines {
70+
fmt.Println(line)
71+
lineCounter++
72+
}
73+
} else {
74+
// Using bufio scanner here for memory-efficient line-by-line reading.
75+
for scanner.Scan() {
76+
fmt.Println(scanner.Text())
77+
lineCounter++
78+
}
6979
}
7080

7181
// Print totals if flag is set
7282
if viper.GetBool("totals") {
73-
fmt.Printf("\n%s is %s and contains %d records.", logFile, formatFileSize(stat.Size()), lineCounter)
83+
if lineCounter == 1 {
84+
fmt.Printf("\n%s is %s. %d record was printed.\n", logFile, formatFileSize(stat.Size()), lineCounter)
85+
} else {
86+
fmt.Printf("\n%s is %s. %d records were printed.\n", logFile, formatFileSize(stat.Size()), lineCounter)
87+
}
7488
}
7589

7690
// Check for errors during scanning

0 commit comments

Comments
 (0)