output is a Go library that provides an easy way for command-line oriented programs to handle console writing, error writing, and logging (but agnostic as to the choice of logging framework). It also provides a simple way to verify what is written to those writers.
Execute this:
go get github.com/majohn-r/output
In main, create a Bus implementation and a Logger implementation. Here is an example that uses the https://github.com/sirupsen/logrus library to implement logging:
func main() {
// the Bus created by output.NewDefaultBus() neither knows nor cares about
// how logging actually works - that's the purview of the Logger
// implementation it uses.
o := output.NewDefaultBus(ProductionLogger{})
runProgramLogic(o, os.Args)
}
func runProgramLogic(o output.Bus, args []string) {
// any functions called should have the Bus passed in if they, or any
// function they call, needs to write output or do any logging
o.ConsolePrintf("hello world: %v\n", args)
}
type ProductionLogger struct {}
// Trace outputs a trace log message
func (ProductionLogger) Trace(msg string, fields map[string]any) {
logrus.WithFields(fields).Trace(msg)
}
// Debug outputs a debug log message
func (ProductionLogger) Debug(msg string, fields map[string]any) {
logrus.WithFields(fields).Debug(msg)
}
// Info outputs an info log message
func (ProductionLogger) Info(msg string, fields map[string]any) {
logrus.WithFields(fields).Info(msg)
}
// Warning outputs a warning log message
func (ProductionLogger) Warning(msg string, fields map[string]any) {
logrus.WithFields(fields).Warning(msg)
}
// Error outputs an error log message
func (ProductionLogger) Error(msg string, fields map[string]any) {
logrus.WithFields(fields).Error(msg)
}
// Panic outputs a panic log message and calls panic()
func (ProductionLogger) Panic(msg string, fields map[string]any) {
logrus.WithFields(fields).Panic(msg)
}
// Fatal outputs a fatal log message and terminates the program
func (ProductionLogger) Fatal(msg string, fields map[string]any) {
logrus.WithFields(fields).Fatal(msg)
}
In the test code, the output can be checked like this:
func Test_runProgramLogic {
tests := map[string]struct {
name string
args []string
output.WantedRecording
}{
"test case": {
args: []string{"hi" "12" "true"},
WantedRecording: output.WantedRecording{
Console: "hello world: [hi 12 true]",
},
},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
o := NewRecorder()
runProgramLogic(o, tt.args)
if issues, ok := o.Verify(tt.WantedRecording); !ok {
for _, issue := range issues {
t.Errorf("runProgramLogic() %s", issue)
}
}
})
}
}
Documentation beyond this file can be obtained by running ./build.sh doc
, or
go here:
https://pkg.go.dev/github.com/majohn-r/output
- Fork the repository (
https://github.com/majohn-r/output/fork
). - Create a feature branch (
git checkout -b my-new-feature
). - Commit your changes (
git commit -am 'Add some feature'
). - Push to the branch (
git push origin my-new-feature
). - Create a new Pull Request.
These are the minimum standards:
- run [
./build.sh preCommit
] with no errors and 100% coverage on tests. - update CHANGELOG.md with a brief description of the change(s).
Reference an issue in the first line of the commit message:
(#1234) fix that nagging problem
In the example above, 1234 is the issue number this commit reference.
This library adheres to Semantic Versioning standards, so it will be very helpful if the details in the commit message make clear whether the changes require a minor or major release bump.