A collection of libraries that are useful for implementing Go services, libraries, and more.
Please read the CONTRIBUTING.md document for guidelines on developing and contributing changes.
Please see individual packages in the generated documentation for overviews on each.
Please see Code review comments, go proverbs and Idiomatic Go.
When logging errors, use log.Debug(ctx, "some debug event", events.NewErrorInfo(err))
instead of using log.F{"error": err}
. NewErrorInfo logs errors using outreach naming conventions and logs stack traces.
Context is often abused for thread-local state. There are very few legitimate uses for this (tracing is one of those).
Prefer the gobox log package. This logs data in a structured format suitable for outreach Go services.
Do not use the following pattern:
message := fmt.Sprintf("working on org: %s", model.Org.ShortName)
log.Info(ctx, message, modelInfo)
The first arg of log.XXX
calls should be a literal string so we can
quickly find out where a log message comes from. The rest of the args
can hold any structured data we want. The
events
package exposes a few common logging structures.
See go generate:
For example, given this snippet,
package painkiller
//go:generate ./scripts/gobin.sh golang.org/x/tools/cmd/[email protected] -type=Pill
type Pill int
const (
Placebo Pill = iota
Aspirin
Ibuprofen
Paracetamol
Acetaminophen = Paracetamol
)
running go generate ./...
from the root of the repo will create the
file pill_string.go, in package painkiller, containing a definition of
func (Pill) String() string
which can be used to get the string
representation of the enum.
A suggested workflow is to run go generate ./...
from the root of the repo before sending PRs out.
Org information can be logged with standard naming conventions using:
orgInfo := events.Org{Bento: xyz, DatabaseHost: ...}
log.Debug(ctx, "doing xyz", orgInfo)
In most cases, though you probably have some other model struct which has this info. In those cases, the preferred route is to make those model types themselves loggable:
type Model struct {...}
func (m *Model) MarshalLog(addField func(key string, value interface{}) {
m.Org().MarshalLog(addField)
... add any custom fields you want: addField("myCustomField", m.CustomInfo)...
}
func (m *Model) Org() events.Org {
return events.Org{...}
}
Now Model
can be used in logs like so:
var myModel m
log.Debug(ctx, "doing xyz", myModel)
Better still is to generate the MarshalLog function using struct tags