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

Add Metric Instruments API #161

Merged
merged 11 commits into from
Jul 27, 2020
Merged

Conversation

ankit-bhargava
Copy link
Contributor

@ankit-bhargava ankit-bhargava commented Jul 8, 2020

This PR includes API support for metric instruments which are used to capture metrics data from an application. All instruments descend from a base Instrument class which contains basic information such as the name and description. Base classes for bound synchronous, unbound synchronous, and asynchronous instruments specify the required methods for their respective derived types. The framework for observer callbacks which are necessary in asynchronous instrument recording is also added.

Since C++ is strongly typed, every instrument type comes in an Int and Double variant. Per the minimal implementation design guidelines, a suite of no-op instruments is provided which can be injected into code without causing any compilation or runtime errors. This has been verified through unit tests found in noop_instrument_test.cc.

Questions

Ideally, the "bind" function in the base SynchronousInstrument class would be virtual and overriden at each subsequent level below it. I was hoping to use covariant return types to accomplish this so that the bin function for an IntCounter for example could return a pointer to a BoundIntCounter while still conforming to the inheritance pattern. I was unable to do this because shared pointers are not afforded the same leniency in return types, so I would have to dynamic cast in order to achieve the same result. As such, I simply hide the function in the base class rather than overriding. If there is a better solution, please let me know.

@codecov
Copy link

codecov bot commented Jul 8, 2020

Codecov Report

Merging #161 into master will decrease coverage by 3.38%.
The diff coverage is 58.90%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #161      +/-   ##
==========================================
- Coverage   95.68%   92.30%   -3.39%     
==========================================
  Files          96      101       +5     
  Lines        2877     3169     +292     
==========================================
+ Hits         2753     2925     +172     
- Misses        124      244     +120     
Impacted Files Coverage Δ
...pi/include/opentelemetry/metrics/observer_result.h 0.00% <0.00%> (ø)
api/include/opentelemetry/metrics/noop.h 31.46% <28.88%> (-43.54%) ⬇️
...i/include/opentelemetry/metrics/sync_instruments.h 66.66% <66.66%> (ø)
api/include/opentelemetry/metrics/instrument.h 73.33% <73.33%> (ø)
api/test/metrics/noop_instrument_test.cc 89.65% <89.65%> (ø)
.../include/opentelemetry/metrics/async_instruments.h 100.00% <100.00%> (ø)
... and 1 more

@ankit-bhargava ankit-bhargava marked this pull request as ready for review July 8, 2020 16:55
@ankit-bhargava ankit-bhargava requested a review from a team July 8, 2020 16:55
Copy link
Contributor

@lykkin lykkin left a comment

Choose a reason for hiding this comment

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

Looks solid! Mostly type related questions. Will revisit again when I have more time.

virtual void observe(int value, const trace::KeyValueIterable &labels) {}
};

class DoubleValueObserver : public AsynchronousInstrument
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like there are a lot of these that only differ based on the type of value that is accepted by the observe method. Could this be generalized through templating or macros?

I'm also fine leaving as is and updating if/when there is reason to (e.g reduction of duplicated methods added to each of the instruments).

* @param value is the numerical representation of the metric being captured
* @return void
*/
virtual void update(nostd::variant<int, double> value) final {}
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see a situation where you would want to change the type you are calling update with after constructing the instrument, would it make sense to template the instrument class and use its type here? That way you don't have any overhead at runtime to unwrap the value.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Our initial hesitance with templates was that they aren't restrictive enough given that we only want to support int and double types. That said, I think you make a great point and I'll reevaluate with my team as it does reduce overhead and cut down on duplicate code.

If I were to template, would I then be responsible for checking that the user picks a suitable type (perhaps by using something like <type_traits>) or expect them to use the instruments with only ints and doubles as intended?

Copy link
Contributor

Choose a reason for hiding this comment

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

Using traits could be one way to go. The compiler errors for using an unsupported type would be pretty gross in this situation, I don't know how much we want to worry about that though.

Alternatively, you could break them out into their own classes with specific types they accept, like DoubleInstrument, and IntInstrument. Code duplication in that case seems pretty rough.

We definitely want to help the user out where possible by putting some guard rails up on the types they can use, one way or another.

}

// Return the instrument name
virtual nostd::string_view GetName() { return nostd::string_view(""); }
Copy link
Member

Choose a reason for hiding this comment

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

Do we want the default implementation or this could be pure virtual?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll make that change, though the tradeoff is substantial code duplication in the noop instruments further down the road.


/**
* Captures data by activating the callback function associated with the
* instrument and storing its return value. Callbacks for asychronous
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* instrument and storing its return value. Callbacks for asychronous
* instrument and storing its return value. Callbacks for asynchronous

};

} // namespace metrics
OPENTELEMETRY_END_NAMESPACE
Copy link
Member

Choose a reason for hiding this comment

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

nit: add a blank line before EOF.

Copy link
Member

@reyang reyang left a comment

Choose a reason for hiding this comment

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

LGTM.

Two non-blocking things:

  • We might want to cover float and short besides double and int for memory efficiency consideration (e.g. especially if we have lots of dimensions).
  • We might need to leverage C++ template to reduce the duplicated code.

@ankit-bhargava
Copy link
Contributor Author

I will template this before we merge; it should address the major concerns raised here.

@reyang
Copy link
Member

reyang commented Jul 18, 2020

@ankit-bhargava if refactoring this PR into template code takes too much time, I'm okay with merge it to unblock the other work. Please let me know.

@reyang reyang added the pr:please-merge This PR is ready to be merged by a Maintainer (rebased, CI passed, has enough valid approvals, etc.) label Jul 18, 2020
@ankit-bhargava ankit-bhargava marked this pull request as draft July 21, 2020 15:46
@reyang
Copy link
Member

reyang commented Jul 21, 2020

@ankit-bhargava would you rebase? Thanks.

@ankit-bhargava ankit-bhargava changed the title Add Metric Instruments API Add Metric Instruments API [WIP] Jul 23, 2020
@ankit-bhargava
Copy link
Contributor Author

Rebased with some changes

@ankit-bhargava ankit-bhargava changed the title Add Metric Instruments API [WIP] Add Metric Instruments API Jul 24, 2020
@ankit-bhargava ankit-bhargava marked this pull request as ready for review July 24, 2020 18:26
@reyang reyang merged commit ed69456 into open-telemetry:master Jul 27, 2020
ziqizh pushed a commit to ziqizh/opentelemetry-cpp that referenced this pull request Jul 31, 2020
ziqizh pushed a commit to ziqizh/opentelemetry-cpp that referenced this pull request Jul 31, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr:please-merge This PR is ready to be merged by a Maintainer (rebased, CI passed, has enough valid approvals, etc.)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants