Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce Observer and SpanObserver #94

Merged
merged 7 commits into from Mar 2, 2017
Merged

Introduce Observer and SpanObserver #94

merged 7 commits into from Mar 2, 2017

Conversation

yurishkuro
Copy link
Member

@yurishkuro yurishkuro commented Feb 17, 2017

Intended to add observer to emit RPC metrics.

@black-adder @badiib

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.5%) to 81.324% when pulling 789b3a2 on observer into fe7c905 on master.

1 similar comment
@coveralls
Copy link

Coverage Status

Coverage decreased (-0.5%) to 81.324% when pulling 789b3a2 on observer into fe7c905 on master.

observer.go Outdated
for _, obs := range o.observers {
obs.OnSetTag(key, value)
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: extra line here.

@oibe
Copy link

oibe commented Feb 17, 2017

Why do we have a method like "OnSetTag", but not something like "OnSetLog"?

Copy link
Contributor

@black-adder black-adder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@oibe the current use case for the observer is for metrics which needs tags, operationName, and startime to build the metrics name. If in the future we need further functionality for an observer, we can add OnSetLog.

LGTM, I'm still not completely sure why observer trumps decorator in this case but this looks good.

observer.go Outdated
OnFinish(options opentracing.FinishOptions)
}

// observer is a disatcher to other observers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo


// noopSpanObserver is used when there are no observers registered on the Tracer
// or none of them returns span observers from OnStartSpan.
var noopSpanObserver = spanObserver{}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this implement SpanObserver funcs?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it does

spanObs := obs.OnStartSpan(operationName, options)
if spanObs != nil {
if spanObservers == nil {
spanObservers = make([]SpanObserver, 0, len(o.observers))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this what we want? what if spanObs is nil for 1 out of len(o.observers)? we allocate more mem than needed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you have a better suggestion?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't we get rid of L40:L42?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you use append() the first capacity of the slice is 2, then it's doubled when it needs to grow. So it's quite possible that in your approach (a) even more memory is allocated than needed, and what's worse (b) potentially more than one memory allocation happens should the slice needs to be extended.

In my approach you get no more than one allocation, and the memory (a pointer) is only wasted if some observers are not interested in the span. I don't think this memory waste is that critical, the service would need to keep a lot of spans in-flight for this to matter

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't you tired of always being right?

@yurishkuro
Copy link
Member Author

@oibe we can add onSetLog if/when this becomes necessary. Right now there's no use case for it so I am not adding it. Also, logs API is quite verbose, it's not clear what the callback should look like.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.4%) to 81.449% when pulling ea99d0f on observer into fe7c905 on master.

1 similar comment
@coveralls
Copy link

Coverage Status

Coverage decreased (-0.4%) to 81.449% when pulling ea99d0f on observer into fe7c905 on master.

Copy link

@badiib badiib left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, the point i made does not apply to this diff directly.

startTime := options.StartTime
if startTime.IsZero() {
startTime = t.timeNow()
if options.StartTime.IsZero() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why test for this? If we are testing that FinishTime is zero, and StartTime is also zero, the failure of a startTime to be set will be apparent in the UI, is a visible (and ugly) bug.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A span must have a start time. But options.startTime is an optional parameter, we do not expect most users to set it.

@yurishkuro
Copy link
Member Author

I'm still not completely sure why observer trumps decorator in this case but this looks good.

@black-adder cf. #103 (rpcmetrics/observer.go). There is not a lot of difference with the decorator, but

  1. there is no need for delegation to the real span, which means less overhead across the board
  2. observer does not need to unwrap start options into a struct, which is a duplicated work. In particular, it does not need to make additional calls to time.Now()

@coveralls
Copy link

Coverage Status

Coverage increased (+0.4%) to 82.244% when pulling e75f4bf on observer into fe7c905 on master.

1 similar comment
@coveralls
Copy link

Coverage Status

Coverage increased (+0.4%) to 82.244% when pulling e75f4bf on observer into fe7c905 on master.

hkshaw1990 added a commit to hkshaw1990/opentracing-go that referenced this pull request Mar 1, 2017
Metrics are useful to gain insights in a distributed application. But
there can be a lot of metrics in different domains. Adding such metrics
to any one (client) tracer breaks cross platform compatibility. This
commit adds a new observer and span observer API which defines a
standard interface to add such metrics. To expose the metrics, one would
have to implement the observer interface. The (client) tracers would
just  have to install callbacks for methods such as StartSpan,
SetOperationName, SetTag and Finish. The registered callbacks would then
be called on the span events if an observer is created.

This is based on the work done by Yuri here :
jaegertracing/jaeger-client-go#94

Signed-off-by: Yuri Shkuro <yurishkuro@users.noreply.github.com>
Signed-off-by: Hemant Kumar <hemant@linux.vnet.ibm.com>
@yurishkuro yurishkuro changed the title RFC: Introduce Observer and SpanObserver Introduce Observer and SpanObserver Mar 1, 2017
@coveralls
Copy link

Coverage Status

Coverage increased (+0.09%) to 82.085% when pulling bbfe8c1 on observer into 2505ffc on master.

1 similar comment
@coveralls
Copy link

Coverage Status

Coverage increased (+0.09%) to 82.085% when pulling bbfe8c1 on observer into 2505ffc on master.


type testObserver struct{}

type testSpanObserver struct {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to create a test struct vs using "mockery"? Is it just because this is simpler?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the clients, we want them as lightweight as possible, the fewer deps the better

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@oibe is there a reason to use mockery instead of creating a struct?

@yurishkuro yurishkuro merged commit 0505b4d into master Mar 2, 2017
hkshaw1990 added a commit to hkshaw1990/zipkin-go-opentracing that referenced this pull request Mar 21, 2017
Metrics are useful to gain insights in a distributed application. But
there can be a lot of metrics in different domains. Adding such metrics
from one domain (metrics exporter pkg) into zipkin is not good for
cross platform compatibility.
This commit adds a new observer and span observer API which defines a
standard interface to add such metrics. To expose the metrics, one would
have to implement the observer interface in the metrics
exporter. zipkin will need to implement this interface and install
callbacks for methods such as StartSpan, SetOperationName, SetTag and
Finish. The registered callbacks would then be called on the span events
if an observer is created.

This is based on the work done by Yuri here :
jaegertracing/jaeger-client-go#94

Signed-off-by: Yuri Shkuro <yurishkuro@users.noreply.github.com>
Signed-off-by: Hemant Kumar <hemant@linux.vnet.ibm.com>
@yurishkuro yurishkuro deleted the observer branch May 5, 2021 21:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants