-
-
Notifications
You must be signed in to change notification settings - Fork 358
docs: add example to count ERROR lines in a log file (#236) #243
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
0aaf8b9
c30c52d
e432526
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| 2026-06-19 12:00:00 [INFO] Starting application... | ||
| 2026-06-19 12:01:05 [WARN] Low memory warning | ||
| 2026-06-19 12:02:10 [ERROR] Database connection failed | ||
| 2026-06-19 12:03:15 [INFO] Retrying database connection... | ||
| 2026-06-19 12:04:20 [ERROR] Retries exhausted. Could not connect to database. | ||
| 2026-06-19 12:05:00 [INFO] Shutting down application. |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,26 @@ | ||||||||
| //go:build ignore | ||||||||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm wondering if we actually need this. I mean, it's absolutely correct in the sense that this file isn't part of the Does it do us any harm to omit the build tag in examples?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question — I tried it, and removing the build tag does break things: with both count_errors.go and filter_csv.go declaring func main() in the same examples/ directory, To keep them copy-paste-able without the tag, my instinct is to give each example its own subdirectory (examples/count_errors/main.go, examples/filter_csv/main.go) — scales cleanly and
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we're working against the grain of Go a little bit here, aren't we? It's actually quite awkward to include a copypastable program in a Go module that doesn't cause a Maybe what we should do instead is use Go's built-in example mechanism. For example (sorry), we could add this to func Example_count_lines() {
count, err := script.File("examples/app.log").Match("ERROR").CountLines()
if err != nil {
panic(err)
}
fmt.Printf("Number of ERROR lines: %d\n", count)
}
func Example_filter_csv() {
// Column splits on whitespace, so turn the comma into a space first,
// then take the first field (the server name).
_, err := script.File("examples/servers.csv").Match("DOWN").Replace(",", " ").Column(1).Stdout()
if err != nil {
panic(err)
}
}As you probably know, because the function names start with
We can put the data files in the |
||||||||
|
|
||||||||
| // Counts the lines containing "ERROR" in a log file. | ||||||||
| // | ||||||||
| // Run it from the repository root: | ||||||||
| // | ||||||||
| // go run examples/count_errors.go | ||||||||
| // | ||||||||
| // Equivalent shell command: | ||||||||
| // | ||||||||
| // grep ERROR examples/app.log | wc -l | ||||||||
| package main | ||||||||
|
|
||||||||
| import ( | ||||||||
| "fmt" | ||||||||
|
|
||||||||
| "github.com/bitfield/script" | ||||||||
| ) | ||||||||
|
|
||||||||
| func main() { | ||||||||
| count, err := script.File("examples/app.log").Match("ERROR").CountLines() | ||||||||
| if err != nil { | ||||||||
| panic(err) | ||||||||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, panicking on errors makes sense for an example because we don't want to clutter up the program with error handling paperwork. But, again, I've learned over the years that whatever you show people is exactly what they'll do, word for word. It's no good saying “Obviously for real programs you wouldn't use Instead, even when it's not directly relevant to the principle I'm demonstrating, I've got into the habit of writing the code that shows what I think is best practice:
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do — switching to fmt.Fprintln(os.Stderr, err) + os.Exit(1) when I apply the restructure. |
||||||||
| } | ||||||||
| fmt.Printf("Number of ERROR lines: %d\n", count) | ||||||||
| } | ||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| //go:build ignore | ||
|
|
||
| // Prints the names of servers whose status is "DOWN", read from a CSV file. | ||
| // | ||
| // Run it from the repository root: | ||
| // | ||
| // go run examples/filter_csv.go | ||
| // | ||
| // Equivalent shell command: | ||
| // | ||
| // grep DOWN examples/servers.csv | cut -d, -f1 | ||
| package main | ||
|
|
||
| import ( | ||
| "github.com/bitfield/script" | ||
| ) | ||
|
|
||
| func main() { | ||
| // Column splits on whitespace, so turn the comma into a space first, | ||
| // then take the first field (the server name). | ||
| _, err := script.File("examples/servers.csv").Match("DOWN").Replace(",", " ").Column(1).Stdout() | ||
| if err != nil { | ||
| panic(err) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| server1,UP | ||
| server2,DOWN | ||
| server3,DOWN | ||
| server4,UP | ||
| server5,DOWN |

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my books I use a listing link convention something like this:
We can use that style for all the other linked examples to come, and perhaps this first time mention the
examplesdirectory:What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the (Listing
name) convention — I'll use the directory-mention version for this first link and that style for the rest, once we settle the layout.