Documentation ¶
Overview ¶
Package report provides a simple log and tracing interface.
Info & Action logging methods to record information or actionable errors. StartSpan & EndSpan methods to record trace information. Runtime Golang stats are gathered via RuntimeEvery. Flexible writer interface provided, with StdOut JSON & Honeycomb exporters included. Log metrics aggregated and exposed via Count for log interface tests.
See Also ¶
https://opentracing.io/docs/overview/spans/ https://docs.honeycomb.io/working-with-data/tracing/ https://docs.honeycomb.io/working-with-data/tracing/send-trace-data/
Example ¶
package main import ( "fmt" "github.com/robtuley/report" ) func main() { // setup logging output log := report.New("example") log.Baggage("timestamp", "2017-05-20T21:00:24.2+01:00") // to make output deterministic log.Export(report.StdOutJSON()) defer log.Close() // ticker daemon execution log.Info("example.start", report.Data{}) seq := 0 for i := 0; i < 3; i++ { log.Info("example.tick", report.Data{"sequence": seq}) seq = seq + 1 } log.Info("example.stop", report.Data{}) // validate if log.Count("example.tick") != 3 { // your own log validation... fmt.Print("Ooops! example.tick should be 3") } if err := log.Err(); err != nil { // your own log validation... fmt.Print(err) } }
Output: {"name":"example.start","service_name":"example","timestamp":"2017-05-20T21:00:24.2+01:00","type":"info"} {"name":"example.tick","sequence":0,"service_name":"example","timestamp":"2017-05-20T21:00:24.2+01:00","type":"info"} {"name":"example.tick","sequence":1,"service_name":"example","timestamp":"2017-05-20T21:00:24.2+01:00","type":"info"} {"name":"example.tick","sequence":2,"service_name":"example","timestamp":"2017-05-20T21:00:24.2+01:00","type":"info"} {"name":"example.stop","service_name":"example","timestamp":"2017-05-20T21:00:24.2+01:00","type":"info"}
Index ¶
- type Data
- type Exporter
- type Logger
- func (l *Logger) Action(event string, payload Data) <-chan int
- func (l *Logger) Baggage(key string, value interface{})
- func (l *Logger) Close()
- func (l *Logger) Count(event string) int
- func (l *Logger) Err() error
- func (l *Logger) Export(e Exporter)
- func (l *Logger) Info(event string, payload Data) <-chan int
- func (l *Logger) RuntimeEvery(duration time.Duration)
- func (l *Logger) Send(d Data) error
- func (l *Logger) Trace(s Span) <-chan int
- type Span
- type SpanOption
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Data ¶
type Data map[string]interface{}
Data is a string-keyed map of unstructured data relevant to the event
type Exporter ¶
Exporter exports events to an external service
type Logger ¶
type Logger struct {
// contains filtered or unexported fields
}
Logger is the central logging agent on which to register events
func New ¶
New creates an instance of a logging agent
logger := report.New("myAppName") logger.Export(report.StdOutJSON()) defer logger.Stop()
func (*Logger) Action ¶
Action events that need intervention or resolving.
Example ¶
package main import ( "errors" "fmt" "github.com/robtuley/report" ) func main() { // setup logging output log := report.New("example") log.Baggage("timestamp", "2017-05-20T21:00:24.2+01:00") // to make output deterministic log.Export(report.StdOutJSON()) defer log.Close() // for example we get an error... err := errors.New("Failed to parse JSON") // normal usage is simple to call log.Action log.Action("json.unparseable", report.Data{"error": err.Error()}) // if you want to block until the logline is written, consume from the returned channel // (useful if you intend to shutdown as a result of this error) <-log.Action("json.unparseable", report.Data{"error": err.Error()}) // LastError can be used to validate if an actionable event was logged if err := log.Err(); err != nil { fmt.Println(err.Error()) } }
Output: {"error":"Failed to parse JSON","name":"json.unparseable","service_name":"example","timestamp":"2017-05-20T21:00:24.2+01:00","type":"action"} {"error":"Failed to parse JSON","name":"json.unparseable","service_name":"example","timestamp":"2017-05-20T21:00:24.2+01:00","type":"action"} Actionable event: json.unparseable
func (*Logger) Count ¶
Count returns the number of log events of a particular type since startup
Example ¶
package main import ( "fmt" "github.com/robtuley/report" ) func main() { log := report.New("example") defer log.Close() log.Info("http.response.200", report.Data{}) log.Info("http.response.404", report.Data{}) log.Info("http.response.200", report.Data{}) fmt.Printf("404 response count is %d", log.Count("http.response.404")) if err := log.Err(); err != nil { fmt.Print(err) } }
Output: 404 response count is 1
func (*Logger) Err ¶
Err returns the last Actionable log event or encoding error if either occurred
Example ¶
package main import ( "fmt" "github.com/robtuley/report" ) func main() { log := report.New("example") log.Export(report.StdOutJSON()) defer log.Close() // this log line has errored, but to prevent error handling clutter // the library interface requires you need to check error states // separately using Logger.LastError() <-log.Info("encoding.fail", report.Data{ "unencodeable": make(chan int), }) // check whether there has been any logging errors if err := log.Err(); err != nil { fmt.Println(err.Error()) } }
Output: Error sending encoding.fail: json: unsupported type: chan int
func (*Logger) Export ¶
Export configures an external service to receive log events
Example ¶
package main import ( "bytes" "fmt" "github.com/robtuley/report" ) func main() { // want to write to 2 logfiles, represented here as 2 buffers b1 := &bytes.Buffer{} b2 := &bytes.Buffer{} // setup logging output log := report.New("example") log.Baggage("timestamp", "2017-05-20T21:00:24.2+01:00") // to make output deterministic defer log.Close() // configure 2 writers log.Export(report.JSON(b1)) log.Export(report.JSON(b2)) // log something <-log.Info("http.response", report.Data{"status": 404, "request": "/nopage"}) // output the 2 log files, note these have been written in parallel which // is why they are kept separate in this example until the end fmt.Print(b1) fmt.Print(b2) if err := log.Err(); err != nil { fmt.Print(err) } }
Output: {"name":"http.response","request":"/nopage","service_name":"example","status":404,"timestamp":"2017-05-20T21:00:24.2+01:00","type":"info"} {"name":"http.response","request":"/nopage","service_name":"example","status":404,"timestamp":"2017-05-20T21:00:24.2+01:00","type":"info"}
func (*Logger) Info ¶
Info logs event that provide telemetry measures or context to any events requiring action.
Example ¶
package main import ( "fmt" "github.com/robtuley/report" ) func main() { // setup logging output log := report.New("example") log.Baggage("timestamp", "2017-05-20T21:00:24.2+01:00") // to make output deterministic log.Export(report.StdOutJSON()) defer log.Close() // normal usage is simple to call log.Info log.Info("http.response", report.Data{"status": 200, "request": "/page1"}) log.Info("http.response", report.Data{"status": 200, "request": "/page2"}) // if you want to block until the logline is written, consume from the returned channel <-log.Info("http.response", report.Data{"status": 404, "request": "/nopage"}) if err := log.Err(); err != nil { fmt.Print(err) } }
Output: {"name":"http.response","request":"/page1","service_name":"example","status":200,"timestamp":"2017-05-20T21:00:24.2+01:00","type":"info"} {"name":"http.response","request":"/page2","service_name":"example","status":200,"timestamp":"2017-05-20T21:00:24.2+01:00","type":"info"} {"name":"http.response","request":"/nopage","service_name":"example","status":404,"timestamp":"2017-05-20T21:00:24.2+01:00","type":"info"}
func (*Logger) RuntimeEvery ¶
RuntimeEvery records runtime stats at the specified interval
log := report.New(report.StdOutJSON(), report.Data{"service": "myAppName"}) log.RuntimeEvery(time.Second*10)
type Span ¶
type Span struct {
// contains filtered or unexported fields
}
Span represents a trace span
func (Span) FollowedBy ¶
FollowedBy adds a followed by span
type SpanOption ¶
SpanOption is a option to modify a span
func ParentSpanID ¶
func ParentSpanID(id string) SpanOption
ParentSpanID option specifies the parent span ID for a span