Skip to content

Commit

Permalink
Initial observer API (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
hkshaw1990 authored and yurishkuro committed Jun 15, 2017
1 parent 9065214 commit a761e77
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 1 deletion.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright {yyyy} {name of copyright owner}
Copyright (c) 2017 opentracing-contrib

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# An Observer API for OpenTracing-go Tracers

OTObserver can be used to watch the span events like StartSpan(),
SetOperationName(), SetTag() and Finish(). A need for observers
arose when information (metrics) more than just the latency information was
required for the spans, in the distributed tracers. But, there can be a lot
of metrics in different domains and adding such metrics to any one (client)
tracer breaks cross-platform compatibility. There are various ways to
avoid such issues, however, an observer pattern is cleaner and provides loose
coupling between the packages exporting metrics (on span events) and the
tracer.

This information can be in the form of hardware metrics, RPC metrics,
useful metrics exported out of the kernel or other metrics, profiled for a
span. These additional metrics can help us in getting better Root-cause
analysis. With that being said, its not just for calculation of metrics,
it can be used for anything which needs watching the span events.

## Installation and Usage

The `otobserver` package provides an API to watch span's events and define
callbacks for these events. This API would be a functional option to a
tracer constructor that passes an Observer. 3rd party packages (who want to
watch the span events) should actually implement this observer API.
To do that, first fetch the package using go get :

```
go get -v github.com/opentracing-contrib/go-observer
```

and say :

```go
import "github.com/opentracing-contrib/go-observer"
```

and then, define the required span event callbacks. These registered
callbacks would then be called on span events if an observer is created.
Tracer may allow registering multiple observers. Have a look at the [jaeger's observer](https://github.com/uber/jaeger-client-go/blob/master/observer.go).

With the required setup implemented in the backend tracers, packages
watching the span events need to implement the observer api defining what
they need to do for the observed span events.

## Span events

An observer registered with this api, can observe for the following four
span events :

```go
StartSpan()
SetOperationName()
SetTag()
Finish()
```

### Tradeoffs

As noble as our thoughts might be in fetching additional metrics (other than
latency) for a span using an observer, there are some overhead costs. Not all
observers need to observe all the span events, in which case, we may have
to keep some callback functions empty. In effect, we will still call these
functions, and that will incur unnecessary overhead. To know more about this
and other tradeoffs, see this [discussion](https://github.com/opentracing/opentracing-go/pull/135#discussion_r105497329).
33 changes: 33 additions & 0 deletions observer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// This project is licensed under the Apache License 2.0, see LICENSE.

package otobserver

// Observer can be registered with a Tracer to recieve notifications
// about new Spans. Tracers are not required to support the Observer API.
// The actual registration depends on the implementation, which might look
// like the below e.g :
// observer := myobserver.NewObserver()
// tracer := client.NewTracer(..., client.WithObserver(observer))
//
type Observer interface {
// Create and return a span observer. Called when a span starts.
// E.g :
// func StartSpan(opName string, opts ...opentracing.StartSpanOption) {
// var sp opentracing.Span
// sso := opentracing.StartSpanOptions{}
// var spObs otobserver.SpanObserver = observer.OnStartSpan(span, opName, sso)
// ...
// }
OnStartSpan(sp Span, operationName string, options StartSpanOptions) SpanObserver
}

// SpanObserver is created by the Observer and receives notifications about
// other Span events.
type SpanObserver interface {
// Callback called from opentracing.Span.SetOperationName()
OnSetOperationName(operationName string)
// Callback called from opentracing.Span.SetTag()
OnSetTag(key string, value interface{})
// Callback called from opentracing.Span.Finish()
OnFinish(options FinishOptions)
}

0 comments on commit a761e77

Please sign in to comment.