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