instana

package module
v1.4.16 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 9, 2019 License: MIT Imports: 26 Imported by: 0

README

golang banner 2017-07-11

Instana Go Sensor

go-sensor requires Go version 1.7 or greater.

The Instana Go sensor consists of two parts:

Build Status OpenTracing Badge

Common Operations

The Instana Go sensor offers a set of quick features to support tracing of the most common operations like handling HTTP requests and executing HTTP requests.

To create an instance of the Instana sensor just request a new instance using the instana.NewSensor factory method and providing the name of the application. It is recommended to use a single Instana only. The sensor implementation is fully thread-safe and can be shared by multiple threads.

var sensor = instana.NewSensor("my-service")

A full example can be found under the examples folder in example/webserver/instana/http.go.

HTTP Server Handlers

With support to wrap a http.HandlerFunc, Instana quickly adds the possibility to trace requests and collect child spans, executed in the context of the request span.

Minimal changes are required for Instana to be able to capture the necessary information. By simply wrapping the currently existing http.HandlerFunc Instana collects and injects necessary information automatically.

That said, a simple handler function like the following will simple be wrapped and registered like normal.

For your own preference registering the handler and wrapping it can be two separate steps or a single one. The following example code shows both versions, starting with two steps.

func myHandler(w http.ResponseWriter, req *http.Request) {
  time.Sleep(450 * time.Millisecond)
}

// Doing registration and wrapping in two separate steps
func main() {
  http.HandleFunc(
      "/path/to/handler",
      sensor.TracingHandler("myHandler", myHandler),
  )
}

// Doing registration and wrapping in a single step
func main() {
  http.HandleFunc(
      sensor.TraceHandler("myHandler", "/path/to/handler", myHandler),
  )
}
Executing HTTP Requests

Requesting data or information from other, often external systems, is commonly implemented through HTTP requests. To make sure traces contain all spans, especially over all the different systems, certain span information have to be injected into the HTTP request headers before sending it out. Instana's Go sensor provides support to automate this process as much as possible.

To have Instana inject information into the request headers, create the http.Request as normal and wrap it with the Instana sensor function as in the following example.

req, err := http.NewRequest("GET", url, nil)
client := &http.Client{}
resp, err := sensor.TracingHttpRequest(
    "myExternalCall",
    parentRequest,
    req,
    client
)

The provided parentRequest is the incoming request from the request handler (see above) and provides the necessary tracing and span information to create a child span and inject it into the request.

The request is, after injection, executing using the provided http.Client instance. Like the normal client.Do operation, the call will return a http.Response instance or an error proving information of the failure reason.

Sensor

To use sensor only without tracing ability, import the instana package and run

instana.InitSensor(opt)

in your main function. The init function takes an Options object with the following optional fields:

  • Service - global service name that will be used to identify the program in the Instana backend
  • AgentHost, AgentPort - default to localhost:42699, set the coordinates of the Instana proxy agent
  • LogLevel - one of Error, Warn, Info or Debug

Once initialized, the sensor will try to connect to the given Instana agent and in case of connection success will send metrics and snapshot information through the agent to the backend.

OpenTracing

In case you want to use the OpenTracing tracer, it will automatically initialize the sensor and thus also activate the metrics stream. To activate the global tracer, run for example

ot.InitGlobalTracer(instana.NewTracerWithOptions(&instana.Options{
	Service:  SERVICE,
	LogLevel: instana.DEBUG}))

in your main function. The tracer takes the same options that the sensor takes for initialization, described above.

The tracer is able to protocol and piggyback OpenTracing baggage, tags and logs. Only text mapping is implemented yet, binary is not supported. Also, the tracer tries to map the OpenTracing spans to the Instana model based on OpenTracing recommended tags. See simple example for details on how recommended tags are used.

The Instana tracer will remap OpenTracing HTTP headers into Instana Headers, so parallel use with some other OpenTracing model is not possible. The Instana tracer is based on the OpenTracing Go basictracer with necessary modifications to map to the Instana tracing model. Also, sampling isn't implemented yet and will be focus of future work.

Events API

The sensor, be it instantiated explicitly or implicitly through the tracer, provides a simple wrapper API to send events to Instana as described in its documentation.

To learn more, see the Events API document in this repository.

Examples

Following examples are included in the examples folder:

  • ot-simple/simple.go - Demonstrates basic usage of the tracer
  • webserver/http.go - Demonstrates how http server and client should be instrumented
  • rpc/rpc.go - Demonstrates a basic RPC service
  • event/ - Demonstrates usage of the event API

Documentation

Index

Constants

View Source
const (
	SeverityChange   severity = -1
	SeverityWarning  severity = 5
	SeverityCritical severity = 10
)

Severity values for events sent to the instana agent

View Source
const (
	ServicePlugin = "com.instana.forge.connection.http.logical.LogicalWebApp"
	ServiceHost   = ""
)

Defaults for the Event API

View Source
const (
	Error = 0
	Warn  = 1
	Info  = 2
	Debug = 3
)

Valid log levels

View Source
const (
	// FieldT Trace ID header
	FieldT = "x-instana-t"
	// FieldS Span ID header
	FieldS = "x-instana-s"
	// FieldL Level header
	FieldL = "x-instana-l"
	// FieldB OT Baggage header
	FieldB = "x-instana-b-"
)

Instana header constants

View Source
const (
	DefaultMaxBufferedSpans = 1000
	DefaultForceSpanSendAt  = 500
)
View Source
const (
	// MaxLogsPerSpan The maximum number of logs allowed on a span.
	MaxLogsPerSpan = 2
)
View Source
const (
	// SnapshotPeriod is the amount of time in seconds between snapshot reports.
	SnapshotPeriod = 600
)

Variables

This section is empty.

Functions

func EumSnippet

func EumSnippet(apiKey string, traceID string, meta map[string]string) string

EumSnippet generates javascript code to initialize JavaScript agent

func Header2ID

func Header2ID(header string) (int64, error)

Header2ID converts an header context value into an Instana ID. More specifically, this converts an unsigned 64 bit hex value into a signed 64bit integer.

func ID2Header

func ID2Header(id int64) (string, error)

ID2Header converts an Instana ID to a value that can be used in context propagation (such as HTTP headers). More specifically, this converts a signed 64 bit integer into an unsigned hex string.

func InitSensor

func InitSensor(options *Options)

InitSensor Intializes the sensor (without tracing) to begin collecting and reporting metrics.

func NewTracer

func NewTracer() ot.Tracer

NewTracer Get a new Tracer with the default options applied.

func NewTracerWithEverything

func NewTracerWithEverything(options *Options, recorder SpanRecorder) ot.Tracer

NewTracerWithEverything Get a new Tracer with the works.

func NewTracerWithOptions

func NewTracerWithOptions(options *Options) ot.Tracer

NewTracerWithOptions Get a new Tracer with the specified options.

func SendDefaultServiceEvent

func SendDefaultServiceEvent(title string, text string, sev severity, duration time.Duration)

SendDefaultServiceEvent sends a default event which already contains the service and host

func SendHostEvent

func SendHostEvent(title string, text string, sev severity, duration time.Duration)

SendHostEvent send an event on the current host

func SendServiceEvent

func SendServiceEvent(service string, title string, text string, sev severity, duration time.Duration)

SendServiceEvent send an event on a specific service

Types

type ContextSensitiveFunc added in v1.4.14

type ContextSensitiveFunc func(span ot.Span, ctx context.Context)

type EntityData

type EntityData struct {
	PID      int        `json:"pid"`
	Snapshot *SnapshotS `json:"snapshot,omitempty"`
	Metrics  *MetricsS  `json:"metrics"`
}

EntityData struct to hold snapshot data.

type EventData

type EventData struct {
	Title string `json:"title"`
	Text  string `json:"text"`
	// Duration in milliseconds
	Duration int `json:"duration"`
	// Severity with value of -1, 5, 10 : see type severity
	Severity int    `json:"severity"`
	Plugin   string `json:"plugin,omitempty"`
	ID       string `json:"id,omitempty"`
	Host     string `json:"host"`
}

EventData is the construct serialized for the host agent

type MemoryS

type MemoryS struct {
	Alloc         uint64  `json:"alloc"`
	TotalAlloc    uint64  `json:"total_alloc"`
	Sys           uint64  `json:"sys"`
	Lookups       uint64  `json:"lookups"`
	Mallocs       uint64  `json:"mallocs"`
	Frees         uint64  `json:"frees"`
	HeapAlloc     uint64  `json:"heap_alloc"`
	HeapSys       uint64  `json:"heap_sys"`
	HeapIdle      uint64  `json:"heap_idle"`
	HeapInuse     uint64  `json:"heap_in_use"`
	HeapReleased  uint64  `json:"heap_released"`
	HeapObjects   uint64  `json:"heap_objects"`
	PauseTotalNs  uint64  `json:"pause_total_ns"`
	PauseNs       uint64  `json:"pause_ns"`
	NumGC         uint32  `json:"num_gc"`
	GCCPUFraction float64 `json:"gc_cpu_fraction"`
}

MemoryS struct to hold snapshot data.

type MetricsS

type MetricsS struct {
	CgoCall   int64    `json:"cgo_call"`
	Goroutine int      `json:"goroutine"`
	Memory    *MemoryS `json:"memory"`
}

MetricsS struct to hold snapshot data.

type Options

type Options struct {
	Service                     string
	AgentHost                   string
	AgentPort                   int
	MaxBufferedSpans            int
	ForceTransmissionStartingAt int
	LogLevel                    int
}

Options allows the user to configure the to-be-initialized sensor

type Recorder

type Recorder struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

Recorder accepts spans, processes and queues them for delivery to the backend.

func NewRecorder

func NewRecorder() *Recorder

NewRecorder Establish a Recorder span recorder

func NewTestRecorder

func NewTestRecorder() *Recorder

NewTestRecorder Establish a new span recorder used for testing

func (*Recorder) GetQueuedSpans

func (r *Recorder) GetQueuedSpans() []jsonSpan

GetQueuedSpans returns a copy of the queued spans and clears the queue.

func (*Recorder) QueuedSpansCount

func (r *Recorder) QueuedSpansCount() int

QueuedSpansCount returns the number of queued spans

Used only in tests currently.

func (*Recorder) RecordSpan

func (r *Recorder) RecordSpan(span *spanS)

RecordSpan accepts spans to be recorded and and added to the span queue for eventual reporting to the host agent.

type Sensor added in v1.4.14

type Sensor struct {
	// contains filtered or unexported fields
}

func NewSensor added in v1.4.14

func NewSensor(serviceName string) *Sensor

Creates a new Instana sensor instance which can be used to inject tracing information into requests.

func (*Sensor) TraceHandler added in v1.4.14

func (s *Sensor) TraceHandler(name, pattern string, handler http.HandlerFunc) (string, http.HandlerFunc)

It is similar to TracingHandler in regards, that it wraps an existing http.HandlerFunc into a named instance to support capturing tracing information and data. It, however, provides a neater way to register the handler with existing frameworks by returning not only the wrapper, but also the URL-pattern to react on.

func (*Sensor) TracingHandler added in v1.4.14

func (s *Sensor) TracingHandler(name string, handler http.HandlerFunc) http.HandlerFunc

Wraps an existing http.HandlerFunc into a named instance to support capturing tracing information and response data.

func (*Sensor) TracingHttpRequest added in v1.4.14

func (s *Sensor) TracingHttpRequest(name string, parent, req *http.Request, client http.Client) (res *http.Response, err error)

Wraps an existing http.Request instance into a named instance to inject tracing and span header information into the actual HTTP wire transfer.

func (*Sensor) WithTracingContext added in v1.4.14

func (s *Sensor) WithTracingContext(name string, w http.ResponseWriter, req *http.Request, f ContextSensitiveFunc)

Executes the given ContextSensitiveFunc and executes it under the scope of a newly created context.Context, that provides access to the parent span as 'parentSpan'.

func (*Sensor) WithTracingSpan added in v1.4.14

func (s *Sensor) WithTracingSpan(name string, w http.ResponseWriter, req *http.Request, f SpanSensitiveFunc)

Executes the given SpanSensitiveFunc and executes it under the scope of a child span, which is# injected as an argument when calling the function.

type SnapshotS

type SnapshotS struct {
	Name     string `json:"name"`
	Version  string `json:"version"`
	Root     string `json:"goroot"`
	MaxProcs int    `json:"maxprocs"`
	Compiler string `json:"compiler"`
	NumCPU   int    `json:"cpu"`
}

SnapshotS struct to hold snapshot data.

type SpanContext

type SpanContext struct {
	// A probabilistically unique identifier for a [multi-span] trace.
	TraceID int64

	// A probabilistically unique identifier for a span.
	SpanID int64

	// Whether the trace is sampled.
	Sampled bool

	// The span's associated baggage.
	Baggage map[string]string // initialized on first use
}

SpanContext holds the basic Span metadata.

func (SpanContext) ForeachBaggageItem

func (c SpanContext) ForeachBaggageItem(handler func(k, v string) bool)

ForeachBaggageItem belongs to the opentracing.SpanContext interface

func (SpanContext) WithBaggageItem

func (c SpanContext) WithBaggageItem(key, val string) SpanContext

WithBaggageItem returns an entirely new SpanContext with the given key:value baggage pair set.

type SpanRecorder

type SpanRecorder interface {
	// Implementations must determine whether and where to store `span`.
	RecordSpan(span *spanS)
}

A SpanRecorder handles all of the `RawSpan` data generated via an associated `Tracer` (see `NewStandardTracer`) instance. It also names the containing process and provides access to a straightforward tag map.

type SpanSensitiveFunc added in v1.4.14

type SpanSensitiveFunc func(span ot.Span)

type Tracer

type Tracer interface {
	opentracing.Tracer

	// Options gets the Options used in New() or NewWithOptions().
	Options() TracerOptions
}

Tracer extends the opentracing.Tracer interface

type TracerOptions

type TracerOptions struct {
	// ShouldSample is a function which is called when creating a new Span and
	// determines whether that Span is sampled. The randomized TraceID is supplied
	// to allow deterministic sampling decisions to be made across different nodes.
	// For example,
	//
	//   func(traceID uint64) { return traceID % 64 == 0 }
	//
	// samples every 64th trace on average.
	ShouldSample func(traceID int64) bool
	// TrimUnsampledSpans turns potentially expensive operations on unsampled
	// Spans into no-ops. More precisely, tags and log events are silently
	// discarded. If NewSpanEventListener is set, the callbacks will still fire.
	TrimUnsampledSpans bool
	// Recorder receives Spans which have been finished.
	Recorder SpanRecorder
	// NewSpanEventListener can be used to enhance the tracer by effectively
	// attaching external code to trace events. See NetTraceIntegrator for a
	// practical example, and event.go for the list of possible events.
	NewSpanEventListener func() func(bt.SpanEvent)
	// DropAllLogs turns log events on all Spans into no-ops.
	// If NewSpanEventListener is set, the callbacks will still fire.
	DropAllLogs bool
	// MaxLogsPerSpan limits the number of Logs in a span (if set to a nonzero
	// value). If a span has more logs than this value, logs are dropped as
	// necessary (and replaced with a log describing how many were dropped).
	//
	// About half of the MaxLogPerSpan logs kept are the oldest logs, and about
	// half are the newest logs.
	//
	// If NewSpanEventListener is set, the callbacks will still fire for all log
	// events. This value is ignored if DropAllLogs is true.
	MaxLogsPerSpan int
	// DebugAssertSingleGoroutine internally records the ID of the goroutine
	// creating each Span and verifies that no operation is carried out on
	// it on a different goroutine.
	// Provided strictly for development purposes.
	// Passing Spans between goroutine without proper synchronization often
	// results in use-after-Finish() errors. For a simple example, consider the
	// following pseudocode:
	//
	//  func (s *Server) Handle(req http.Request) error {
	//    sp := s.StartSpan("server")
	//    defer sp.Finish()
	//    wait := s.queueProcessing(opentracing.ContextWithSpan(context.Background(), sp), req)
	//    select {
	//    case resp := <-wait:
	//      return resp.Error
	//    case <-time.After(10*time.Second):
	//      sp.LogEvent("timed out waiting for processing")
	//      return ErrTimedOut
	//    }
	//  }
	//
	// This looks reasonable at first, but a request which spends more than ten
	// seconds in the queue is abandoned by the main goroutine and its trace
	// finished, leading to use-after-finish when the request is finally
	// processed. Note also that even joining on to a finished Span via
	// StartSpanWithOptions constitutes an illegal operation.
	//
	// Code bases which do not require (or decide they do not want) Spans to
	// be passed across goroutine boundaries can run with this flag enabled in
	// tests to increase their chances of spotting wrong-doers.
	DebugAssertSingleGoroutine bool
	// DebugAssertUseAfterFinish is provided strictly for development purposes.
	// When set, it attempts to exacerbate issues emanating from use of Spans
	// after calling Finish by running additional assertions.
	DebugAssertUseAfterFinish bool
	// EnableSpanPool enables the use of a pool, so that the tracer reuses spans
	// after Finish has been called on it. Adds a slight performance gain as it
	// reduces allocations. However, if you have any use-after-finish race
	// conditions the code may panic.
	EnableSpanPool bool
}

TracerOptions allows creating a customized Tracer via NewWithOptions. The object must not be updated when there is an active tracer using it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL